Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Potential concurrency issue when Integer object is used as a lock in synchronized block

While working on a multi-threading program and I observed very strange behavior.

When Integer object is used as a lock then it seems that multiple threads can be in synchronized block. Even thought that is not expected.

If I use any other static member like 's', 'o' and 'c' define in below program, it works as expected.

Code-

public class MyThread extends Thread{
    private static Integer ii=1;                        //Works fine
    private static Integer i=1;
    private static String s="1";                        //Works fine
    private static Object o= new Object();              //Works fine
    private static Class<MyThread> c= MyThread.class;   //Works fine

    public void run(){
        synchronized(i){
            System.out.print(i++ +" ");
            System.out.print(i+"   ");
        }
    }
    public static void main(String[] str) throws InterruptedException{
        for(int i=0;i<100;i++){
            MyThread t= new MyThread();
            t.start();
        }
        Thread.sleep(100);
        System.out.println();
        MyThread t= new MyThread();
        t.start();t.join();
        if(i!=102)
            System.out.println("fail");
    }
}

output-

2 3   3 4   5 6   8 9   9 10   10 11 12   12 13   13 14   14 15   16 17   1 17   15 17   12   17 18   18 20   20 21   21 22   7 22 6 23   4 23   23 24   24 25   25 26   23   22   19 27   26 27   27 28   28 29   29 30   30 31   31 32   32 33   33 34   34 35   35 36   36 37   37 38   38 39   39 41   40 41 42   42   42 43   43 44 45   45   45 48   47 48   46 48   48 49   49 50   50 51   51 52   52 53   53 54   54 55   55 56   56 57   57 58   58 59   59 60   60 61   61 62   62 63 64   64 65   64   65 66   66 67   68 69   69 70   67 70   70 71   71 72   72 73   73 75   74 76   75 76   76 77   77 79 80   78 80   80   80 83 84   82 85   85 86   86 87   87 88   88 89   89 90   81 94   93 94   92 94   91 94   90 94   84   94 96   96 98   98 99   84 99   97 99   95 99   99 100   100 101   
101 102  

As you can see when it printed "10 11 12" there were two threads executing in synchronized block.

Is it I am doing something wrong or am I missing something?

Does it have to do with some optimization behind the scene? Because if I used 'ii' for locking everything works perfectly.

Also when 'i' is used it does print 'fail' but RARELY.

Below is java version used to run the program. java -version java version "1.7.0_51" Java(TM) SE Runtime Environment (build 1.7.0_51-b13) Java HotSpot(TM) Client VM (build 24.51-b03, mixed mode, sharing)

You can use below program to run the program to run this bunch of times and see the results.

public class MyThread extends Thread{
    private static Integer ii=1;
    private static Integer i=1;
    private static String s="1";
    private static Object o= new Object();
    private static Class<MyThread> c= MyThread.class;

    public void run(){
        synchronized(ii){
            System.out.print(i++ +" ");
            System.out.print(i+"   ");
        }
    }
    public static void main(String[] str) throws InterruptedException{
        for(int j=0;j<100;j++){
            for(int i=0;i<100;i++){
                MyThread t= new MyThread();
                t.start();
            }
            Thread.sleep(50);
            System.out.println();
            MyThread t= new MyThread();
            t.start();t.join();
            if(i!=102)
                System.out.println("fail");
            Thread.sleep(50);
            i=1;
            System.out.println();
        }
    }
}
like image 968
JavaDeveloper Avatar asked Feb 13 '23 16:02

JavaDeveloper


2 Answers

This

i++

is equivalent to

i = Integer.valueOf(i.intValue() + 1)

In other words, i is now referencing a different object, different than the one you are originally synchronizing on.

If a thread happens to get to the synchronized block after the i has changed, it will also get in because it acquires the monitor on a different object.

Because if I used 'ii' for locking everything works perfectly.

You aren't changing the reference to ii anywhere.

like image 70
Sotirios Delimanolis Avatar answered Feb 16 '23 05:02

Sotirios Delimanolis


This is exactly why locks should be declared final. And this is an example of how you can shoot yourself in the foot.

like image 26
Giovanni Botta Avatar answered Feb 16 '23 05:02

Giovanni Botta