摘要:貓說多線程之內(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)可見性與volatile實(shí)現(xiàn)可見性。
我們會(huì)談及幾個(gè)點(diǎn):指令重排序、as-if-serial語義、volatile使用注意事項(xiàng)等
首先我們要了解下兩個(gè)名詞,有點(diǎn)術(shù)語的感覺,雖然我不喜歡那些專業(yè)名詞,但是你懂得···
可見性:通俗的說就是一個(gè)線程對(duì)共享變量值的修改,可以及時(shí)地被其它線程看到
共享變量:即一個(gè)變量在多個(gè)線程的工作內(nèi)存中存在副本,則這個(gè)變量就是這些線程的共享變量
這兩個(gè)名稱理解起來還不算難,對(duì)吧?那么我們來看看更加專業(yè)化的名詞,我其實(shí)更希望有具象化的有趣的名詞來代替,原諒我的文學(xué)水平有限。
Java內(nèi)存模型(JMM)
Java Memory Model 描述了Java程序中各種變量(這里指線程共享變量,你已經(jīng)理解上面的第二個(gè)名詞了)的訪問規(guī)則,以及在JVM中將變量存儲(chǔ)到內(nèi)存和從內(nèi)存中讀取出變量這樣的底層細(xì)節(jié),就像細(xì)胞要在血管中流動(dòng)一樣(一個(gè)不及格的比喻),它要求所有的變量都存儲(chǔ)在主內(nèi)存中,每個(gè)線程都有自己獨(dú)立的工作內(nèi)存,里面保存該線程使用到的變量的副本(也就是主內(nèi)存中該變量的一份拷貝)
讓我們來看看圖型吧,文字有時(shí)理解起來比起圖片要來的復(fù)雜,至少我是這樣覺得,我更喜歡具象化的說明
對(duì)于色調(diào)我一直有不同于別人的理解,原諒我看似混亂的搭配。
綜合的總結(jié)一下,結(jié)合上圖還有之前說的,我們可以定出一下兩個(gè)原則(或許可以輕松一點(diǎn)的說,而不是用“原則”)
1、線程對(duì)共享變量的所有操作都必須在自己的工作空間(內(nèi)存)中進(jìn)行,不能直接從主內(nèi)存中讀寫
2、不同線程之間無法直接訪問其他線程中工作內(nèi)存中的變量,線程間的變量值的傳遞需要通過主內(nèi)存來完成
以上兩句可能需要細(xì)細(xì)體會(huì),就像你喝咖啡后不會(huì)立馬喝下一口一樣,請(qǐng)回味一下。
由此我們可以模糊但又明確的指出共享變量可見性實(shí)現(xiàn)的原理
結(jié)合下圖一同說明下,線程A對(duì)共享變量的修改要想被線程B即使看到,需要經(jīng)過如下兩步:
1、把工作內(nèi)存A中更新過的共享變量刷新到主內(nèi)存中
2、將主內(nèi)存中最新的共享變量的值更新到工作內(nèi)存B中
讓我們重新回到主題,Java語言層面支持的可見性實(shí)現(xiàn)方式:
——synchronized
——volatile
而由以上的篇幅講解你也知道了實(shí)現(xiàn)共享變量的可見性,需要保證兩點(diǎn):
1、線程修改后的共享變量值能夠及時(shí)從其工作內(nèi)存中刷新到主內(nèi)存中
2、其他線程能夠及時(shí)把共享變量的最新值從主內(nèi)存更新到自己的工作內(nèi)存中
synchronized可以實(shí)現(xiàn)在于它的性質(zhì):原子性(同步性)、可見性
JMM(看到這個(gè)單詞時(shí)或許你應(yīng)該想到前面的中文含義)關(guān)于synchronized有這樣的一些規(guī)定:
1、線程解鎖前,必須把共享變量的最新值刷新到主內(nèi)存中
2、線程加鎖時(shí),將清空工作內(nèi)存中共享變量的值,在使用共享變量時(shí)需要從主內(nèi)存中重新讀取最新的值
(需要注意的是,加鎖與解鎖需要同一把鎖,這讓我想到了Redis,你想到了什么呢?)
我們可精華的提升下,即線程解鎖前對(duì)共享變量的修改在下次加鎖時(shí)對(duì)其他線程是可見的
讓我們大致看看線程執(zhí)行互斥代碼(即以上的描述)的過程:
1、獲得互斥鎖
2、清空工作內(nèi)存
3、從主內(nèi)存拷貝變量的最新副本到工作內(nèi)存
4、執(zhí)行代碼
5、將更改后的共享變量的值刷新到主內(nèi)存
6、釋放互斥鎖
(請(qǐng)自己思考一次,不要把5、6步的順序顛倒了哦)
本文未完~,請(qǐng)期待下篇。
【Java貓說】Java多線程之內(nèi)存可見性(下篇)
歡迎你留言討論屬于你的見解,畢竟每個(gè)人的味蕾都不一樣,這杯咖啡有吸引到你嗎?
(好像又是一個(gè)槽糕的比喻)
本文已轉(zhuǎn)載個(gè)人技術(shù)公眾號(hào):UncleCatMySelf
歡迎留言討論與點(diǎn)贊
上一篇推薦:【Java貓說】主數(shù)據(jù)類型和引用
下一篇推薦:【Java貓說】Java多線程之內(nèi)存可見性(下篇)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/71652.html
摘要:閱讀本文約分鐘上一次我們說到互斥代碼的實(shí)現(xiàn)過程,如果有忘記或不清楚的可以去上篇看看。貓說多線程之內(nèi)存可見性上篇今天我們了解下重排序。 閱讀本文約3分鐘 上一次我們說到synchronized互斥代碼的實(shí)現(xiàn)過程,如果有忘記或不清楚的可以去上篇看看?!綣ava貓說】Java多線程之內(nèi)存可見性(上篇) 今天我們了解下重排序。 其使代碼書寫的順序與實(shí)現(xiàn)執(zhí)行的順序不同,指令重排序是編譯器或處理...
摘要:閱讀本文約分鐘變量有兩種主數(shù)據(jù)類型和引用。主數(shù)據(jù)類型用來保存基本類型的值,包括整數(shù),布爾和浮點(diǎn)數(shù)等,而對(duì)象引用保存的是對(duì)象的引用。而在中,主數(shù)據(jù)類型也有不用的大小與名稱。 閱讀本文約2.3分鐘 變量有兩種:primitive主數(shù)據(jù)類型和引用。 Java注重類型。它不會(huì)讓你做出把長頸鹿類型變量裝進(jìn)兔子類型變量中這種詭異又危險(xiǎn)的舉動(dòng)——如果有人對(duì)長頸鹿調(diào)用跳躍這個(gè)方法會(huì)發(fā)生什么悲劇?并且...
摘要:閱讀本文約分鐘對(duì)象的行為,這里的對(duì)象即上一章中的類吧淺意狀態(tài)影響行為,行為影響狀態(tài)這是一個(gè)令人深思的話題了。是通過值傳遞的,也就是說通過拷貝傳遞。聲明一個(gè)類型的變量并賦值為,代表的字節(jié)組合會(huì)放進(jìn)稱為的變量中。 閱讀本文約2分鐘 對(duì)象的行為,這里的對(duì)象即上一章中的類吧(淺意) 狀態(tài)影響行為,行為影響狀態(tài)! 這是一個(gè)令人深思的話題了。 同一類型的每個(gè)對(duì)象能夠有不同的方法行為嗎? 仔細(xì)想一...
閱讀 995·2021-09-26 10:15
閱讀 2081·2021-09-24 10:37
閱讀 2588·2019-08-30 13:46
閱讀 2638·2019-08-30 11:16
閱讀 2427·2019-08-29 10:56
閱讀 2600·2019-08-26 12:24
閱讀 3484·2019-08-23 18:26
閱讀 2669·2019-08-23 15:43