溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java中volatile的工作原理是什么

發(fā)布時間:2021-08-03 14:49:53 來源:億速云 閱讀:143 作者:Leah 欄目:編程語言

Java中volatile的工作原理是什么,相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。

一、前提概要

1、用過這個關(guān)鍵字的童鞋都知道,都知道這個關(guān)鍵字很強大,主要作用是保證變量在多線程之間的可見性;
2、volatile在concurrent包中起著舉足輕重的作用,為大量的并發(fā)類提供了有力的援助;
3、接下來我們從了解CPU緩存開始,然后再深入原理剖析,循序漸進的了解volatile;

二、CPU緩存

2.1 傳輸鏈路

CPU(線程)
--》  CPU緩存(一級、二級、三級緩存等)
--》  主內(nèi)存

大致的傳輸方向就這樣,而且還是必須是雙向傳輸。

2.2 CPU緩存

1、CPU緩存解決了CPU運算速度與內(nèi)存讀者速度不匹配的問題;

2、因為主內(nèi)存訪問通常比較慢,訪問時間大概在幾十到幾百個時鐘,而CPU緩存還有一二三級之分,每個級別的讀者速度雖然很快,
   但還是有訪問速度的區(qū)分,至少比主內(nèi)存的讀者速度快很多,所以CPU緩存它的出現(xiàn)在很大程度上提高了數(shù)據(jù)之間的傳輸;

3、每一級緩存中所存儲的數(shù)據(jù)全部都是下一級緩存中的一部分,這三種緩存的技術(shù)難度和制造成本是相對遞減的,所以其容量也相對遞增;

4、當CPU要讀取一個數(shù)據(jù)時,首先從一級緩存中查找,如果沒有再從二級緩存中查找,如果還是沒有再從三級緩存中或內(nèi)存中查找。
   一般來說每級緩存的命中率大概都有80%左右,也就是說全部數(shù)據(jù)量的80%都可以在一級緩存中找到;

三、原理特性

3.1、可見性

1、淺顯的講,不論線程是如何如何的訪問帶volatile字段的對象,都會訪問到內(nèi)存中最新的一份值,這就是可見性的大致闡述;

2、具體的講,當我們在java代碼中書寫的那行對volatile對象進行寫操作時,JVM會向處理器發(fā)送一條Lock指令,
   Lock指令鎖?。ㄦi總線)確保變量對象所在緩存行數(shù)據(jù)會更新到主內(nèi)存中去,確保更新后如果再有其他線程訪問該對象,
   其他線程一律強制從主內(nèi)存中重新讀取最新的值。

3、因為所有內(nèi)存的傳輸都發(fā)生在一條共享的總線上,并且所有的處理器都能看到這條總線,那么既然所有處理器都能看到這條總線,
   總不至于看見了不干點啥吧?

4、沒錯,每個處理器都會通過一種監(jiān)聽技術(shù),不停的監(jiān)聽總線上傳輸?shù)臄?shù)據(jù),以便來檢查自己緩存中的數(shù)據(jù)是否過期。
   當處理器發(fā)現(xiàn)高速緩存中的數(shù)據(jù)對應(yīng)的內(nèi)存地址被修改,會將該緩存數(shù)據(jù)置為失效,當處理器下次訪問該內(nèi)存地址
   數(shù)據(jù)時,將強制重新從系統(tǒng)內(nèi)存中讀取。

5、而且CPU制造商也曾制定了一個這樣的規(guī)則:當一個CPU修改緩存中的字節(jié)對象時,服務(wù)器中其他CPU會被通知,它們的緩存將視為無效。
   當那些被視為無效變量所在的線程再次訪問字節(jié)對象時,則強制再次從主內(nèi)存中獲取最新值。

6、至于第2點提到Lock鎖總線,其實最初采用鎖總線,雖說能解決問題,但是效率地下,一旦鎖總線,其他CPU就得干等著,
   光看不干效率不行嘛。所以后來優(yōu)化成了鎖緩存,效率也高了,開銷也自然就少了,總之Lock目的很明確,確保鎖住的那份值最新,
   且其他持有該緩存的備份處都得失效,其實這種鎖緩存過程的思想也正是緩存一致性協(xié)議的核心思想。

7、綜上所述,所以不論何時不論何地在哪種多線程環(huán)境下,只要你想獲取被volatile修飾過的字段,都能看到最新的一份值,
   這就是可見性的終極描述。

3.2、有序性

1、淺顯的講,A1,A2,A3三塊代碼先后執(zhí)行,A2有一行代碼被volatile修飾過,那么在被反編譯成指令進行重排序時,A2必須等到A1
   執(zhí)行完了才能開始,但是A1內(nèi)部的指令可以支持重排指令;而A3代碼塊的執(zhí)行必須等到A2執(zhí)行完了才能開始,但是A3內(nèi)部的指令可以支持
   重排指令,這就是有序性,只要A2夾在中間,A2必須等A1執(zhí)行完才能干活,A2沒干完活,A3是不允許開工的。

2、具體的講,Lock前綴指令實際上相當于一個內(nèi)存屏障(也成內(nèi)存柵欄),它確保指令重排序時不會把其后面的指令排到內(nèi)存屏障之前的位置,
   也不會把前面的指令排到內(nèi)存屏障的后面;即在執(zhí)行到內(nèi)存屏障這句指令時,在它前面的操作已經(jīng)全部完成。

3、綜上所述,有序不是我們通常說的自然順序,而是在有volatile修飾時,存在類似尊卑等級的先后有序這么一說。

3.3、非原子性

1、本不該拿到臺面上講是不是屬于volatile的特性,因為我們不能認為僅僅只是因為可見性隨處都是最新值,那么就認為是原子性操作。

2、對于第1種想法,簡直是大錯特錯,因為可見性只是將volatile變量這回主內(nèi)存并使得其他CPU緩存失效,但是不帶代表對volatile變量
   回寫主內(nèi)存的動作和對volatile變量的邏輯操作是捆綁在一起的。因此既要邏輯操作,又要寫回主內(nèi)存,這本來就違背了volatile特性
   的本意,所以volatile并不是原子操作的。

看完上述內(nèi)容,你們掌握Java中volatile的工作原理是什么的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI