[英]Potential concurrency issue when Integer object is used as a lock in synchronized block
在處理多線程程序時,我觀察到了非常奇怪的行為。
當Integer對象用作鎖時,似乎多個線程可以處於同步塊中。 甚至認為這是不可預期的。
如果我在下面的程序中使用任何其他靜態成員,如's','o'和'c',則按預期工作。
碼-
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");
}
}
輸出 -
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
正如您在打印“10 11 12”時所看到的那樣,在同步塊中有兩個線程正在執行。
是我做錯了什么還是我錯過了什么?
它是否與場景背后的優化有關? 因為如果我使用'ii'鎖定一切都很完美。
此外,當使用'i'時,它確實打印'失敗'但是RARELY。
下面是用於運行程序的java版本。 java -version java version“1.7.0_51”Java(TM)SE運行時環境(版本1.7.0_51-b13)Java HotSpot(TM)客戶端VM(版本24.51-b03,混合模式,共享)
您可以使用以下程序運行程序來運行這一堆並查看結果。
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();
}
}
}
這個
i++
相當於
i = Integer.valueOf(i.intValue() + 1)
換句話說, i
現在引用一個不同的對象,與您最初同步的對象不同。
如果一個線程在i
發生變化后碰巧到達synchronized
塊,它也會進入,因為它在另一個對象上獲取了監視器。
因為如果我使用'ii'鎖定一切都很完美。
您沒有在任何地方更改對ii
的引用。
這正是為什么鎖應該被聲明為final
。 這是一個如何用腳射擊自己的例子。
我認為問題在於你通過在synchronized塊中執行i++
來改變'i'的值,這導致每次分配給i
的對象都不同(在Eclipse中檢查它,查看變量的對象id之前並且在增量操作之后)。
Integer
是一個不可變的類。 當你在它上面執行像++
這樣的操作時,你就是在創建一個新實例。 這可能導致線程在不同對象上同步,使它們能夠同時訪問synchronized
塊。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.