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