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();
}
}
}
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.
This is exactly why locks should be declared final
. And this is an example of how you can shoot yourself in the foot.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With