java基礎理論學習筆記(1)——談談對volatile的理解?從可見性、非原子性、禁止指令重排詳細解釋

首先借用陽哥的腦圖:

1、輕量級:是相對jvm的三個特性,volatile只實現了可見性、有序性來說的。

2、可見性:

如下圖:線程工作時,會從堆中(主內存)裏拷貝變量age=25到各自棧中(工作內存),當任一線程如t1修改值爲37,回寫到主內存時,需要保障其他所有線程都獲知主內存的變量age已更新爲37,這就是可見性,即對主內存的修改,得相互知道

內存模型JMM:分爲堆、方法區、棧、寄存器

代碼測試可見性,可利用main線程以及new一個子線程來印證,若未用volatile關鍵字修飾的變量,在子線程更新值後,對於main線程是不可見的,無法得到更新值。而使用了volatile之後,值更新線程間是互相可見的。得證volatile具有可見性。

2、非原子性

原子性:不可分割,完整性,線程在執行某個由多項步驟構成的任務時,中間不可以被加塞打斷,需要讓它完整執行所有步驟。

對於這多項步驟,要麼全部成功,任務完成,要麼就全部都失敗,回退掉。類比數據庫事務的原子性。

非原子性,就表示在線程對變量作業務時,volatile不能保障線程的每個任務的完整執行所有步驟。例如:

執行一個:number++自增運算,其任務有以下步驟:

getfield        //讀
iconst_1	//++常量1
iadd		//加操作
putfield	//寫操作

當高併發時,自增就會出錯。比如某個時刻,有幾個線程同時拿到number的值都是1的時候,第一個線程自增完成做putfield寫操作時,同時其他線程在自己棧空間操作了阻塞在寫操作中,等第一個完成後,陸續其他線程也寫回了2.造成了寫覆蓋。相當於有部分線程的操作失效。

解決方案:1、對該業務過程加鎖(synchronize修飾,但太殺雞用牛刀了);2、用jdk裏面的atomicinteger API(建議),底層是CAS實現的,計算機原子指令

3、禁止指令重排

案例:

重排後,線程1的x取到了線程2初始化的a的值。導致錯誤

volatile有序性原理:

volatile應用場景

在DCL單例模式中(Double-Check-Lock)

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