Problems with the use of java volatile synchronized keywords

topic description

while learning the knowledge of multithreading, the result of the following code is not the same as expected. I can"t see what the problem is. Please take a look at it

.

sources of topics and their own ideas

what I think is that after the end of the program, the value of staticv is an integer 200000, but each time the result is in 19xxxxxxxxx, which is very close, unlike Synchronize. I don"t know what went wrong. In addition, the code is annotated with the location of-sharp, foo is marked by synchronized, and Synchronize is the instance object of SyncObj rather than SyncObjc.class,. Obviously, there are two instance objects that are called without Synchronize. I think it is wrong if volatile is not added. But the result of the execution seems to be the same. Why? I don"t know what went wrong with my understanding. Please give me your advice. Thank you.

related codes

package concurrency;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class SynchronizedTest {

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newCachedThreadPool();
        SyncObj obj1 =new SyncObj();
        SyncObj obj2 =new SyncObj();
        CountDownLatch countDownLatch = new CountDownLatch(20);
        for(int i=0;i<10;iPP) {
            executor.execute(new TT(obj1,countDownLatch));
            executor.execute(new TT(obj2,countDownLatch));
        }

        countDownLatch.await();
        System.out.println("result----------------------"+SyncObj.staticv);
    }
}

class SyncObj {
    public static volatile int staticv = 0; //-sharp-sharp-sharp-sharp-sharp-sharpvolatile
    public  synchronized void foo() {
        for(int i=0;i<1000;iPP) {
            System.out.println(staticv);
            staticvPP;
        }
    }
}

class TT implements Runnable{
    public CountDownLatch countDownLatch;
    public SyncObj obj;
    public TT( SyncObj obj,CountDownLatch countDownLatch) {
        this.obj=obj;
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        for(int i=0;i<100;iPP) {
            obj.foo();
        }
        countDownLatch.countDown();
    }
    
}

The reason for the problem with

is that volatile does not provide atomicity.
staticvPP; is actually a combined operation consisting of a sequence of read-modify-write operations. If thread An and thread B execute staticvPP; at the same time, thread A reads the value of staticv, adds 1, then interrupts, and then thread B reads the value of staticv, adds 1, and then writes to staticv. Thread A then executes, although according to the characteristics of volatile , the value of staticv in thread A has become the value after + 1, but thread A will not read staticv again at this time, but will directly write back the value after reading staticv plus 1 to staticv. As a result, although staticvPP; has been executed twice, in fact, staticv has only increased by 1.

Let's discuss why staticvPP; does not achieve the effect of staticv self-increasing atomicity after wrapping it with synchronized .
the crux of the problem is that you use synchronized at the method level. You have applied for two SyncObj objects. There is no Synchronize relationship between the foo methods of the two objects, but the Synchronize relationship only exists in the foo method of the same object.

it would be correct to change the foo method to this.

public void foo() {
    synchronized (this.getClass()) {
        for(int i=0;i<10000000;iPP) {
            staticvPP;
        }
    }
}

changing the foo method of SyncObj to a static method can solve your problem, because Synchronize cannot be maintained between objects after new multiple SyncObj objects.


class SyncObj {
    public static volatile int staticv = 0; //-sharp-sharp-sharp-sharp-sharp-sharpvolatile
    public static synchronized void foo() {
        for(int i=0;i<1000;iPP) {
            //System.out.println(staticv);
            staticvPP;
        }
    }
}

or you can share a SyncObj object

 SyncObj obj1 =new SyncObj();
 CountDownLatch countDownLatch = new CountDownLatch(20);
 for(int i=0;i<10;iPP) {
            executor.execute(new TT(obj1,countDownLatch));
            executor.execute(new TT(obj1,countDownLatch));
 }

got it. Thank you very much

Menu