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