synchronized 加鎖Integer對象(數據重複)詳解

場景描述:多線程輸出1到100,對靜態Integer對象加鎖,synchronized代碼塊中操做Integer對象,發生線程安全問題(數據重複)java

代碼:數組

public class MyRunnableTest implements Runnable {
    public static Integer i = new Integer(0);

    @Override
    public void run() {
        while(true){
            synchronized (i) {
                if(i<100){
                    i++;
                    System.out.println(Thread.currentThread()+"i = " + i);
                }else {
                    break;
                }
            }
        }
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new MyRunnableTest());
        Thread t2 = new Thread(new MyRunnableTest());
        t1.start();
        t2.start();
    }

}

運行結果:緩存

Thread[Thread-0,5,main]i = 1
Thread[Thread-1,5,main]i = 3
Thread[Thread-1,5,main]i = 4
Thread[Thread-1,5,main]i = 5
Thread[Thread-1,5,main]i = 6
Thread[Thread-0,5,main]i = 5
Thread[Thread-1,5,main]i = 7
Thread[Thread-0,5,main]i = 8
Thread[Thread-1,5,main]i = 9
Thread[Thread-0,5,main]i = 10
Thread[Thread-1,5,main]i = 11
Thread[Thread-0,5,main]i = 12
Thread[Thread-1,5,main]i = 13

 

從運行結果中能夠發現發生了線程安全問題,爲何呢?爲何synchronized無效了。安全

個人排查思路:多線程

一、由於沒有進行任何的額外操做,因此首先定位問題在i++處併發

經過javap分析字節碼命令,總結:ide

能夠看出:i++的實際操做爲:Integer.valueOf(Integer.intValue(i)+1)測試

咱們在看看Integer中vauleOf的源碼:spa

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

cache[]數組初始化: 
  cache = new Integer[(high - low) + 1];
  int j = low;
  for(int k = 0; k < cache.length; k++)
  cache[k] = new Integer(j++);

 

其中low爲-128,hight爲127。能夠了解到,當i的值爲-128~127時,是從IntegerCache中取的(能夠理解爲從緩存中取的),超過部分是new出來的對象。線程

二、目前咱們慢慢開始解開了問題的面紗,每當i發生自增後,所對象改變了,這裏咱們還須要清楚一下,synchronized在鎖對象發生改變時(測試發現,引用類型對象的內在屬性變化不會釋放鎖)會當即釋放鎖。因此這裏就會出現線程安全問題,並且在單核的運行環境下,全部的線程是併發執行而不是並行執行,當咱們運行到system.out.println時,鎖已經釋放了,假如這邊t1線程(當前運行的線程,i=1的狀況)釋放CPU資源,t2執行,這時i等於2(i++以前),當執行到system.out.println時釋放cpu資源(此時i=3),t1執行,i此時已經爲3了,因此輸出3,在釋放cpu資源,t2執行,輸出3,這時出現了輸出重複值的狀況。

相關文章
相關標籤/搜索