synchronized Interger失敗

原因:Synchronized鎖的是對象,也就是identityHashCode所指向的內存地址中的對象實例(根據對象內存地址生成散列值)
下面先看一個demo

static public class MyRunable implements Runnable{
        private Integer ncount = 0;
        public void run() {
            Integer temp = 0;
            //System.out.println("thread id:"+Thread.currentThread().getId()+"count"+ncount+" identityHashCode:"+System.identityHashCode(ncount)+" HashCode:"+ncount.hashCode());
            while (temp <= 100){
                synchronized (ncount){
                    ncount++;
                    temp = ncount;
                    //System.out.println("thread id:"+Thread.currentThread().getId()+"count"+ncount+" identityHashCode:"+System.identityHashCode(ncount)+" HashCode:"+ncount.hashCode());
                    System.out.println("thread id:"+Thread.currentThread().getId()+"count:"+ncount);
                }
                try {
                    Thread.sleep(1000000000);
                }
                catch (Exception e){
                    e.printStackTrace();
                }

            }

        }
    }

 public static void main(String [] args) throws Exception{
        Runnable runnable = new MyRunable();
        Thread thread1 = new Thread(runnable);
        Thread thread2 = new Thread(runnable);
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
    }

結果輸出(如果結果不一致多運行幾次):
在這裏插入圖片描述
發現結果和我們期望不一樣,count的值沒被鎖住。這是爲什麼呢?難道是成員變量的原因?我們將ncount修改成static

 static private Integer ncount = 0;

結果依舊一樣,難道是Integer 類型的問題?,那我們嘗試使用類試試

static public class CA{

    }

static public class MyRunable implements Runnable{
	private CA lock = new CA();
	...
	//synchronized (ncount)
	synchronized (lock){
	...
	}
}

在這裏插入圖片描述

發現替換成類之後結果就符合預期。那麼synchronized Interger爲什麼會失敗呢?看一下線程調用堆棧
在這裏插入圖片描述
上圖中,每一個線程鎖住的資源其實都並非是同一個,這就可以解釋爲什麼對Integer類型進行加鎖仍然是非線程安全的。其實Synchronized鎖的是對象,也就是identityHashCode所指向的內存地址中的對象實例(根據對象內存地址生成散列值)既然Synchronized是根據identityHashCode 所指向的內存地址中的對象實例來鎖的,那麼說明Integer的identityHashCode是發生了變化的,而CA是固定的。下面看日誌:
在這裏插入圖片描述
在這裏插入圖片描述
最後總結下,synchronized(Integer)時,當值發生改變時,基本上每次鎖住的都是不同的對象實例,想要保證線程安全,推薦使用AtomicInteger之類會更靠譜。

參考博客:
https://www.iteye.com/blog/gao-xianglong-2396071

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章