摘要:閱讀本文約分鐘上一次我們說到互斥代碼的實現過程,如果有忘記或不清楚的可以去上篇看看。貓說多線程之內存可見性上篇今天我們了解下重排序。
閱讀本文約“3分鐘”
上一次我們說到synchronized互斥代碼的實現過程,如果有忘記或不清楚的可以去上篇看看。
【Java貓說】Java多線程之內存可見性(上篇)
今天我們了解下重排序。
其使代碼書寫的順序與實現執行的順序不同,指令重排序是編譯器或處理器為了提高程序性能而做的優化,可以分為
1、編譯器優化的重排序(編譯器優化)
2、指令級并行重排序(處理器優化)
3、內存系統的重排序(處理器優化)
而as-if-serial語義原則是指:無論如何重排序,程序執行的結果應該與代碼順序執行的結果一致(Java編譯器、運行時和處理器都會保證Java在單線程下遵循as-if-serial語義)
int num1 = 1; int num2 = 2; int sum = num1 + num2;
對于執行的單線程而言,第1、2行的順序可以重排,但第3行不能
由此,重排序并不會給單線程帶來內存可見性問題
但是在多線程中程序交錯執行時,重排序可能會造成內存可見性問題
這里羅列了幾個原因,導致共享變量在線程間不可見的原因:
1、線程的交叉執行(synchronized原子性)
2、重排序結合線程交叉執行(synchronized原子性)
3、共享變量更新后的值沒有在工作內存與主內存間及時更新(synchronized可見性)
而對于另一個對象volatile而言其實現了可見性,但是不能保證原子性(不能保證volatile變量符合操作是的原子性)
深入來說,是通過加入內存屏障和禁止重排序優化來實現的。
1、對volatile變量執行寫操作時,會在寫操作后加一條store屏障指令
2、對volatile變量執行讀操作時,會在讀操作前加入一條load屏障指令
由此我們可以分為讀寫volatile變量的兩種操作。
線程寫volatile變量的過程:
1、改變線程工作內存中volatile變量副本的值
2、將改變后的副本的值從工作內存刷新到主內存
線程讀volatile變量的過程:
1、從主內存中讀取volatile變量的最新值到線程的工作內存中
2、從工作內存中讀取volatile變量的副本
注意:volatile是不能保證原子性的
想要在多線程中安全的使用volatile變量,必須同時滿足一下幾個條件:
1、對變量的寫入操作不依賴其當前值
- 不滿足:number++、count = count * 5 - 滿足:boolean變量、記錄數據變化的變量等
2、該變量沒有包含在具有其他變量的不變式中
- 不滿足:不變式 low < up
最后我們來比較下這兩個對象吧
- volatile不需要加鎖,比synchronized更輕量級,不會阻塞線程 - 從內存可見性角度講,volatile讀相當于加鎖,volatile寫相當于解鎖 - synchronized即能保證可見性,又能保證原子性,而volatile只能保證可見性,無法保證原子性 - volatile沒有synchronized使用的廣泛
本文已轉載個人技術公眾號:UncleCatMySelf
歡迎留言討論與點贊
上一篇推薦:【Java貓說】Java多線程之內存可見性(上篇)
下一篇推薦:【Java貓說】Java對象的行為
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71646.html
摘要:貓說多線程之內存可見性下篇歡迎你留言討論屬于你的見解,畢竟每個人的味蕾都不一樣,這杯咖啡有吸引到你嗎好像又是一個槽糕的比喻本文已轉載個人技術公眾號歡迎留言討論與點贊上一篇推薦貓說主數據類型和引用下一篇推薦貓說多線程之內存可見性下篇 閱讀本文約3分鐘 本文大致講述兩種線程實現的可見性,或許你已經提前想到了,那說明你的基礎很好,我們要聊聊synchronized實現可見性與volatil...
摘要:閱讀本文約分鐘對象的行為,這里的對象即上一章中的類吧淺意狀態影響行為,行為影響狀態這是一個令人深思的話題了。是通過值傳遞的,也就是說通過拷貝傳遞。聲明一個類型的變量并賦值為,代表的字節組合會放進稱為的變量中。 閱讀本文約2分鐘 對象的行為,這里的對象即上一章中的類吧(淺意) 狀態影響行為,行為影響狀態! 這是一個令人深思的話題了。 同一類型的每個對象能夠有不同的方法行為嗎? 仔細想一...
摘要:閱讀本文約分鐘變量有兩種主數據類型和引用。主數據類型用來保存基本類型的值,包括整數,布爾和浮點數等,而對象引用保存的是對象的引用。而在中,主數據類型也有不用的大小與名稱。 閱讀本文約2.3分鐘 變量有兩種:primitive主數據類型和引用。 Java注重類型。它不會讓你做出把長頸鹿類型變量裝進兔子類型變量中這種詭異又危險的舉動——如果有人對長頸鹿調用跳躍這個方法會發生什么悲劇?并且...
閱讀 1618·2021-11-22 13:53
閱讀 2848·2021-11-15 18:10
閱讀 2755·2021-09-23 11:21
閱讀 2491·2019-08-30 15:55
閱讀 475·2019-08-30 13:02
閱讀 752·2019-08-29 17:22
閱讀 1659·2019-08-29 13:56
閱讀 3455·2019-08-29 11:31