你竟然用Integer作為synchronized的鎖對象?


在使用多線程編程時,往往會使用一些手段保證線程安全,也就是加鎖,但是加鎖也必須合理,如使用synchronized對對象加鎖時,如果不注意,還可能發生錯誤的加鎖。

先看一段小測試,在這個小測試中,啟動了1000個線程,每個線程在對integer加1前都先獲得integer的鎖,這看似是線程安全的,並且預期可能會得到1000這個值,而然並不然,在運行多次之后他總是輸出<=1000的值,那么,這犢子是哪出問題了。

 static  Integer integer =new Integer("0");
 static  CountDownLatch mCountDownLatch =new CountDownLatch(1000);
 public static void main(String[] args) throws InterruptedException {
     for (int i = 1; i <=1000; i++) {
         new Thread(()->{
             synchronized (integer){
                 integer++;
                 mCountDownLatch.countDown();
             }
         }).start();
     }
     mCountDownLatch.await();
     System.out.println(integer);
 }

這其實就是上述所說:"錯誤的加鎖對象",也就是Integer作為鎖對象這是個不正確的選擇。

那在說Integer,不少人可能會見過這樣的題。

Integer i1 =125;
Integer i2 =125;
System.out.println(i1==i2);
Integer i3 =135;
Integer i4 =135;
System.out.println(i3==i4);

答案是true,false,這樣的結果是由Integer的緩存導致,在直接對Integer=xxx時候,其實調用了Integer.valueOf,(可以使用javap命令反編譯查看)
在這里插入圖片描述

而Integer.valueOf中,如果參數值在一定范圍內,就從IntegerCache緩存中返回,也就是說在一定范圍內多個相同的值是同一個對象,超出的話則return new Integer(i)返回一個新的Integer。而這個范圍在-128-127,
在這里插入圖片描述
在上面的135顯然不在范圍,則返回的是新對象,又由於==是比較內存地址,所以上述會出現false。如果要比較包裝類是否相等,正確的做法是equals方法,Integer也重寫了equals,判斷內部基本數據類型是否一樣。
在這里插入圖片描述
這樣一來,synchronized(integer)原因就知道了, integer++是創建了一個新的Integer對象,並將引用賦值給integer。因為integer一直在變,線程每次加鎖可能都加在了不同對象的實例上,導致臨界區控制出現問題。

解決辦法也很容易,只要加在一個不變的對象上即可。

static  Integer integer =new Integer("0");
static  CountDownLatch mCountDownLatch =new CountDownLatch(1000);
static  Object sObject= new Object();
public static void main(String[] args) throws InterruptedException {
    for (int i = 1; i <=1000; i++) {
        new Thread(()->{
            synchronized (sObject){
                integer++;
                mCountDownLatch.countDown();
            }
        }).start();
    }
    mCountDownLatch.await();
    System.out.println(integer);
}

(不只Integer,Character、Short、Long也有緩存,但是Float和Double卻沒有)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM