免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
我們所熟悉的java并發(fā)volatile!

我們工程師對這個并發(fā)并不陌生吧,那么這個并發(fā)的關(guān)鍵字volatile是怎樣的呢? 

       個人認為,既然是多線程編程,那我們在平常的學習中,工作中,大部分都接觸到的就是線程安全的概念。而線程安全就會涉及到共享變量的概念,所以首先,我們得弄清楚共享變量是什么,且處理器和內(nèi)存間的數(shù)據(jù)交互機制是如何導(dǎo)致共享變量變得不安全。

共享變量

能夠在多個線程間被多個線程都訪問到的變量,我們稱之為共享變量。共享變量包括所有的實例變量,靜態(tài)變量和數(shù)組元素。他們都被存放在堆內(nèi)存中。

處理器與內(nèi)存的通信機制

大家都知道處理器是用來做計算的,且速度是非??斓?,而內(nèi)存是用來存儲數(shù)據(jù)的,且其訪問速度相比處理器來說,是慢了好幾個級別的。那么當處理器需要處理數(shù)據(jù)時,如果每次都直接從內(nèi)存拿數(shù)據(jù)的話,就會導(dǎo)致效率非常低,因此在現(xiàn)代計算機系統(tǒng)中,處理器是不直接跟內(nèi)存通信的,而是在處理器和內(nèi)存之間設(shè)置了多個緩存,也就是我們常常聽到的L1, L2, L3等高速緩存。

具體架構(gòu)如下所示:

我們所熟悉的java并發(fā)volatile!

java并發(fā)之volatile

memory_processor_communication.png

處理器都是將數(shù)據(jù)從內(nèi)存讀到自己內(nèi)部的緩存中,然后在緩存中對數(shù)據(jù)進行修改等操作,結(jié)束后再由緩存寫到回主存中去。

如果一個共享變量 X,在多線程的情況下,同時被多個處理器讀到各自的緩存中去,當其中一個處理器修改了X的值,改成Y了,先寫回了內(nèi)存,而此時另外一個處理器,又將X改成Z,再寫回內(nèi)存,那么之前的Y就會被覆蓋掉了。

這種情況下,數(shù)據(jù)就已經(jīng)有問題了,這種因為多線程操作而導(dǎo)致的異常問題,通常我們就叫做線程不安全。

我們所熟悉的java并發(fā)volatile!

memory_processor_communication_core1.png

memory_processor_communication_core2.png

如上述兩圖所示,X的變量同時被不同的處理器修改成各自的Y和Z,那么如何避免這種情況呢?

這就涉及到了Java內(nèi)存模型中的可見性的概念。

Java內(nèi)存模型之可見性

可見性,意思就是說,在多線程編程中,某個共享變量在其中一個線程被修改了,其修改結(jié)果要馬上能夠被其他線程看到,拿上面的例子來說,也就是當X在其中一個處理器的緩存中被修改成Y了, 另一個處理器必須能夠馬上知道自己緩存中的X已經(jīng)被修改成Y了,當此處理器要拿此變量去參與計算的時候,必須重新去內(nèi)存中將此變量的值Y讀到緩存中。

而一個變量,如果被聲明成violate,那么其就能保證這種可見性,這就是volatile變量的作用了。

volatile

那么 volatile 變量能夠保證可見性的實現(xiàn)原理是什么?

聲明成volatile的變量,在編譯成匯編指令的時候,會多出以下一行:

0x0bca13ae:lock addl $0x0,(%esp) ;

這一句指令的意思是在寄存器上做一個+0的空操作,但這條指令有個Lock前綴。

而處理器在處理Lock前綴指令時,其實是聲言了處理器的Lock#信號。

在之前的處理器中,Lock#信號會導(dǎo)致傳輸數(shù)據(jù)的總線被鎖定,其他處理器都不能訪問總線,從而保證處理Lock指令的處理器能夠獨享操作數(shù)據(jù)所在的內(nèi)存區(qū)域。

但由于總線被鎖住,其他的處理器都被堵住了,影響多處理器執(zhí)行的效率。在后來的處理器中,聲言Lock#信號的處理器,不會再鎖住總線,而是檢查到數(shù)據(jù)所在的內(nèi)存區(qū)域,如果是在處理器的內(nèi)部緩存中,則會鎖定此緩存區(qū)域,將緩存寫回到內(nèi)存當中,并利用緩存一致性的原則來保證其他處理器中的緩存區(qū)域數(shù)據(jù)的一致性。

緩存一致性

緩存一致性原則會保證一個在緩存中的數(shù)據(jù)被修改了,會保證其他緩存了此數(shù)據(jù)的處理器中的緩存失效,從而讓處理器重新去內(nèi)存中讀取最新修改后的數(shù)據(jù)。

在實際的處理器操作中,各個處理器會一直在總線上嗅探其內(nèi)部緩存區(qū)域中的內(nèi)存地址在其它處理器的操作情況,一旦嗅探到某處理器打算修改某內(nèi)存地址,而此內(nèi)存地址剛好也在自己內(nèi)部的緩存中,則會強制讓自己的緩存無效。當下次訪問此內(nèi)存地址的時候,則重新從內(nèi)存當中讀取新數(shù)據(jù)。

volatile不僅保證了共享變量在多線程間的可見性,其還保證了一定的有序性。

有序性

何謂有序性呢?

事實上,java程序代碼在編譯器階段和處理器執(zhí)行階段,為了優(yōu)化執(zhí)行的效率,有可能會對指令進行重排序。

如果一些指令彼此之間互相不影響,那么就有可能不按照代碼順序執(zhí)行,比如后面的代碼先執(zhí)行,而之前的代碼則慢執(zhí)行,但處理器會保證結(jié)束時的輸出結(jié)果是一致的。

以上的這種情況就說明指令有可能不是有序的。

volatile變量,上面我們看過其匯編指令,會多出一條Lock前綴的指令,這條指令能夠 保證,在這條指令之前的所有指令全部執(zhí)行完畢,而在這條指令之后的所有指令全部未執(zhí)行,也相于在這里立起了一道柵欄,稱之為內(nèi)存柵欄,而更通俗的說法,則是內(nèi)存屏障。

那么有了這道屏障,volatile變量就禁止了指令的重排序,從而保證了指令執(zhí)行的有序性。

所有對volatile變量的讀操作一定發(fā)生在對volatile變量的寫操作之后。這同時也說明了volatile變量在多個線程之間能夠?qū)崿F(xiàn)可見性的原理。所以各種規(guī)定和操作,其實之間互有關(guān)聯(lián),彼此依賴,才能更好地保證指令執(zhí)行的準確和效率。

內(nèi)存屏障

在上面我們也引出了內(nèi)存屏障的概念,也知道了,其實它就是一組處理器的操作指令。

插入一個內(nèi)存屏障,則相當于告訴處理器和編譯器先于這個指令的必須先執(zhí)行,后于這個指令的必須后執(zhí)行。

我們所熟悉的java并發(fā)volatile!

java并發(fā)之volatile

image

內(nèi)存屏障另一個作用是強制更新一次不同CPU的緩存。

例如,一個寫屏障會把這個屏障前寫入的數(shù)據(jù)刷新到緩存,這樣任何試圖讀取該數(shù)據(jù)的線程將得到最新值,而不用考慮到底是被哪個cpu核心或者哪顆CPU執(zhí)行的。

這再仔細一想,不就是上面所說的volatile的作用嗎?

所以,內(nèi)存屏障,可見性,有序性,緩存一致性原則,在java并發(fā)中各種各樣的名詞,本質(zhì)上可能就只是同一種現(xiàn)象或者同一種設(shè)計,從不同的角度觀察和探討所得出的不同的解釋。


想了解更多java資訊的朋友們可以關(guān)注我,定時更新更好的文章給到大家。

加關(guān)注轉(zhuǎn)發(fā),然后再私信小編,獲取一套學習java的教程資料。

記得是點關(guān)注加轉(zhuǎn)發(fā),在私信哦!

我們所熟悉的java并發(fā)volatile!

我們所熟悉的java并發(fā)volatile!

我們所熟悉的java并發(fā)volatile!

我們所熟悉的java并發(fā)volatile!

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
你真的了解 volatile 關(guān)鍵字嗎?
Java并發(fā)專題【5】徹底理解volatile
Java內(nèi)存模型原理,你真的理解嗎?
你真的了解volatile嗎?
深入理解Java內(nèi)存模型(五)——鎖
Java 關(guān)鍵字 volatile 的理解與正確使用 | 干貨分享
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服