0

my program is:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class test implements Runnable{
    private static int i;
    private static volatile Integer vi = 0;
    private static AtomicInteger ai = new AtomicInteger();
    private static Integer si = 0;
    private static int ri;
    private static AtomicInteger flag = new AtomicInteger();
    private Lock lock = new ReentrantLock();
    @Override
    public void run() {
        for(int k=0;k<200000;k++){
            i++;
            vi++;
            ai.incrementAndGet();
            synchronized (si){
                si++;
            }
            lock.lock();
            try{
                ri++;
            }finally {
                lock.unlock();
            }
        }
        flag.incrementAndGet();
    }
    public static void main(String[] args) throws InterruptedException{
        test t1 = new test();
        test t2 = new test();
        ExecutorService exec1 = Executors.newCachedThreadPool();
        ExecutorService exec2 = Executors.newCachedThreadPool();
        exec1.execute(t1);
        exec1.execute(t2);
        while(true){
            if(flag.intValue()==2){
                System.out.println("i>>>>>>"+i);
                System.out.println("vi>>>>>>"+vi);
                System.out.println("ai>>>>>>"+ai);
                System.out.println("si>>>>>>"+si);
                System.out.println("ri>>>>>>"+ri);
                break;
            }
            Thread.sleep(50);
        }
    }
}

the result is:

vi>>>>>>340217
ai>>>>>>400000
si>>>>>>364359
ri>>>>>>397043

could someone help to explain how does this multithread programs works? the result shows that vi is not equal to 400000 which is quite reasonable. but why si and ri is not equal to 400000? si is sychronized and ri is sychronized by locks.

Alfred luo
  • 11
  • 5

2 Answers2

3

You aren't synchronizing access to the variables in the main thread.

You need the same synchronization/lock around the variables in order to guarantee the visibility of updates.

However, your synchronization on si probably doesn't work as you intend, because you keep assigning a new value to that field: synchronized on test.class instead.

Similarly the synchronization conferred by the lock probably doesn't work as you intend, because each test instance has its own lock.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
0

lock is not static, hence each thread uses different instance, as you create two instances of test, hence ri is not synchronized. si is not synchronized, because integer is immutable, but si++ does unboxing, increment and boxing. You should synchronize on another final object that is static for ex. or use one instance of test:

private final Object lockObj = new Object();
...
synchronized(lockObj){
  si++;
}
igorepst
  • 1,230
  • 1
  • 12
  • 20
  • so boxing and unboxing mutate the instance of si?can u describe it in detail? ty. – Alfred luo Apr 11 '19 at 09:59
  • No, as `Integer` is effectively final. However, as you change the reference to `si` object, the synchronization won't work for you - synchronize on another object – igorepst Apr 11 '19 at 10:03
  • 1
    @igorepst [It's `final`](https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html), not "effectively final". More significantly, it's *immutable*. – Andy Turner Apr 11 '19 at 10:07
  • @AndyTurner You're right. I meant immutable. Thanks – igorepst Apr 11 '19 at 10:10
  • @igorepst so boxing and inboxing change the variable that si referer to ,right? – Alfred luo Apr 11 '19 at 10:12
  • @Alfredluo variables refer to *objects*. – Andy Turner Apr 11 '19 at 10:15
  • Basically this goes like this: `Integer -> to int -> increment -> int to Integer -> assign si`. As @AndyTurner wrote the Integer is immutable, hence the instance of it cannot be changed, only a new one may be created and a reference to the new one is assigned – igorepst Apr 11 '19 at 10:15
  • 1
    `si++;` is effectively compiled to `si = Integer.valueOf(si.intValue() + 1);`. – Andy Turner Apr 11 '19 at 10:18
  • at last,i want to know which case shall i use keyword volatile.@AndyTurner – Alfred luo Apr 11 '19 at 11:05
  • @Alfredluo: [The answer about volatile](https://stackoverflow.com/a/106787/407953) – igorepst Apr 11 '19 at 11:24