怎樣正確理解volatile?
volatile是java虛擬機器提供的輕量級的同步機制
三大特徵:
(1)保證可見性
當執行緒對變數進行操作時,必須在工作記憶體中進行,完成後再寫會到主記憶體中。
在寫回主記憶體中後其他執行緒馬上都能看到,就是 可見性
(2)不保證原子性
丟失寫值的情況
(3)禁止指令重拍
JMM記憶體模型
可見性
原子性
有序性
主記憶體:主記憶體是共享記憶體的區域,相當於我們的記憶體條,裡面儲存共享變數,所有執行緒都能訪問
工作記憶體:每個執行緒建立時JVM都會為其建立一個工作記憶體,工作記憶體裡面存放的是該執行緒的私有資料,不能相互訪問,
當執行緒對變數進行操作時,必須在工作記憶體中進行,完成後再寫會到主記憶體中。
在寫回主記憶體中後其他執行緒馬上都能看到,就是可見性
什麼是CAS(compareAndSet)?
比較並交換
AtomicInteger.compareAndSet(期望值,要修改的值)
期望值:從主實體記憶體中的值
執行緒每次修改值的時候都要從主實體記憶體中去獲取並比較是否和期望值相同,如果和期望值相同,則修改成要修改的值,並返回true
CAS底層原理?
unsafe valueoffset(記憶體偏移地址)
Unsafe是CAS的核心類
atomicInteger.getAndIncrement(); 底層原始碼::::: public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); } public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { var5 = this.getIntVolatile(var1, var2); } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }
假設 執行緒A 和 執行緒B 同時執行getAndAddInt操作,
首先執行緒A先從主記憶體中獲取到變數A=3到自己的執行緒記憶體中,
同時執行緒B也從主記憶體中獲取到變數A=3到自己的執行緒記憶體中,
現在AB執行緒中都有一份自己的記憶體變數A=3的副本,
執行緒A透過this.getIntVolatile(var1, var2);
獲取到記憶體中的A=3,這時執行緒A被掛起。
這時執行緒B透過this.getIntVolatile(var1, var2);
獲取到記憶體中的A=3,並執行了this.compareAndSwapInt(var1, var2, var5, var5 + var4)
比較主記憶體中的值也為3,就成功將自己的工作記憶體中的A修改為4並寫回到主記憶體中。
這時執行緒A回覆,執行compareAndSwapIn方法比較,發現自己工作記憶體中的A與主記憶體中的A
不一致,說明已經被其他執行緒修改過了,那執行緒A本次修改失敗,while重新來一遍
執行緒A重新獲取value,因為變數被volatile修飾,所以其他執行緒對他的修改執行緒A總是能看到
(volatile的可見性原理)執行緒A繼續執行compareAndSwapInt進行比較直到成功
缺點:
迴圈時間開銷很大
只能保證一個共享變數的原子操作
ABA問題(狸貓換太子)
CAS演算法是提取記憶體中某時刻的資料並在當下時刻進行比較並替換,這個時間差會導致資料變化
比如T1從記憶體位置V中取出A,這時另一個執行緒T2也取出A,T2 將A–>B,然後T2又將B–>A,這
時T1進行CAS發現記憶體中還是A,然後執行緒T1就操作成功了
解決ABA問題:
原子引用AtomicReference
新增一種機制,修改版本號 AtomicStampedReference(初始值,初始版本號)
atomicStampedReference.compareAndSet(100,101,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69946594/viewspace-2655460/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 理解並正確使用synchronized和volatilesynchronized
- 正確理解CAP理論
- 如何正確理解棧和堆?
- 正確理解 PHP 的過載PHP
- Jtti:怎樣正確處理Redis中的海量資料JttiRedis
- background-position的正確理解方式
- 正確理解memcached,才能更好的使用
- volatile的理解
- 談如何正確理解 IP 資料的覆蓋率,兼談正確率~
- 如何正確理解「指標」和「標籤」指標
- 深入理解volatile
- 徹底理解volatile
- 怎樣理解 cosocket
- 如何正確理解Python培訓?有必要嗎?Python
- Redis 記憶體滿了怎麼辦?這樣設定才正確!Redis記憶體
- 怎樣才是單人遊玩《馬里奧派對》的正確姿勢?
- 怎樣正確的去選擇蘋果企業簽名?看這裡!蘋果
- 正確理解和使用JAVA中的字串常量池Java字串
- 編寫高質量的js之正確理解正規表示式回溯JS
- 怎麼正確釋出dubbo控制檯
- 分散式系統知識分享:正確理解CAP定理分散式
- 快速理解 volatile 關鍵字
- 死磕Java——volatile的理解Java
- 怎麼正確的使用代理IP軟體!
- Java關鍵字volatile的理解Java
- Macbook怎麼關閉磁碟“未正確推出”提示Mac
- win10怎麼樣正確開啟ipv6_win10如何開啟ipv6Win10
- Handler正確用法
- 兩張圖理解volatile關鍵字
- java多執行緒之volatile理解Java執行緒
- 怎樣修改網站產品價格,確保價格準確網站
- 如何正確理解神經網路在NLP領域的運用神經網路
- 智慧|智慧倉儲就是無人倉庫嗎?正確理解很重要
- 理解玩家的正確姿勢:遊戲到底意味著什麼?遊戲
- Troubleshooting 專題 - 問正確的問題 得到正確的答案
- 如何正確部署 QUICUI
- 正確高效使用 GoogleGo
- 居家辦公怎麼樣確保工作效率?