欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

深入淺析Java中的volatile-創(chuàng)新互聯(lián)

深入淺析Java中的volatile?針對這個問題,這篇文章詳細介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

成都創(chuàng)新互聯(lián)公司網(wǎng)站建設(shè)公司是一家服務(wù)多年做網(wǎng)站建設(shè)策劃設(shè)計制作的公司,為廣大用戶提供了網(wǎng)站制作、網(wǎng)站設(shè)計,成都網(wǎng)站設(shè)計,廣告投放,成都做網(wǎng)站選成都創(chuàng)新互聯(lián)公司,貼合企業(yè)需求,高性價比,滿足客戶不同層次的需求一站式服務(wù)歡迎致電。

前言

volatile相關(guān)的知識其實自己一直都是有掌握的,能大概講出一些知識,例如:它可以保證可見性;禁止指令重排。這兩個特性張口就來,但要再往深了問,具體是如何實現(xiàn)這兩個特性的,以及在什么場景下使用volatile,為什么不直接用synchronized這種深入和擴展相關(guān)的問題,就回答的不好了。因為volatile是面試必問的知識,所以這次準備把這部分知識也給啃掉。

系統(tǒng)處理效率與Java內(nèi)存模型

在計算機中,每條程序指令都是在CPU中執(zhí)行的,而CPU執(zhí)行指令的數(shù)據(jù)都是臨時存儲在內(nèi)存中的,但是CPU的執(zhí)行速度遠超內(nèi)存的讀取速度,如果所有的CPU指令都是通過內(nèi)存來讀取數(shù)據(jù)的話那么將大大的降低了系統(tǒng)的處理效率,所以現(xiàn)代計算機系統(tǒng)都不得不加入一層或多層讀寫速度盡可能接近處理器運算速度的高速緩存(Cache)來作為內(nèi)存與處理器之間的緩沖。

將運算需要使用的數(shù)據(jù)復(fù)制到緩存中,讓運算能快速進行,當(dāng)運算結(jié)束后,在從緩存同步回內(nèi)存之中,這樣處理器就無須等待緩慢的內(nèi)存讀寫了。

雖然說增加了高速緩存提高了CPU的處理效率,但是也帶來了新的問題 :

現(xiàn)代計算機都是多核CPU,一開始,內(nèi)存中的變量A的值是1,第一個CPU讀取了數(shù)據(jù),第二個CPU也將數(shù)據(jù)讀取到了自己的高速緩存當(dāng)中,當(dāng)?shù)谝粋€CPU對變量A進行加1操作時,變量A的值變成了2,然后將將變量A的值寫回內(nèi)存中,這時第二個CPU也對變量A進行加1操作時,由于第二個CPU中高速緩存中的值還是1,所以加1操作后的結(jié)果為2,然后第二個CPU又將變量A的值同步回內(nèi)存中,這樣就導(dǎo)致執(zhí)行了兩次加1操作后,變量A的值最終是2,而不是3。
這種被多個CPU訪問的變量,通常稱為共享變量。
而產(chǎn)生的上面的問題,就是引入了高速緩存后的,主內(nèi)存和緩存內(nèi)容不一致的問題。
因為每個處理器有自己的高速緩存,但是它們又共享同一塊主內(nèi)存,所以必然會出現(xiàn)主內(nèi)存不知該以哪個高速緩存中的變量為準的情況。

深入淺析Java中的volatile

上面這個緩存不一致的問題,我們先記下來,繼續(xù)來看Java內(nèi)存模型,其實Java內(nèi)存模型描述的上面講的計算機系統(tǒng)高速緩存和內(nèi)存之間的關(guān)系類似。

Java內(nèi)存模型描述了,各種變量的訪問規(guī)則,以及將變量存儲到內(nèi)存和從內(nèi)存讀取變量的這種底層細節(jié)。

在Java內(nèi)存模型中關(guān)注的變量都是共享變量(實例變量、類變量)。
所有的共享變量都是存儲在主內(nèi)存中的,但是每個線程在訪問變量的時候也都會在自己的工作內(nèi)存(處理器高速緩存)中保留一份共享變量的副本。

Java內(nèi)存模型(Java Memory Model,簡稱JMM)規(guī)定:

線程對變量的所有操作(讀,寫)都必須在工作內(nèi)存中進行,不能直接操作主內(nèi)存中的數(shù)據(jù)。
不同線程之間 也不能直接訪問對方工作內(nèi)存中的變量,線程間的變量值傳遞必須通過主內(nèi)存進行中轉(zhuǎn)傳遞。
在JMM中工作內(nèi)存和主內(nèi)存的關(guān)系如下圖:

深入淺析Java中的volatile

Volatile的可見性(保證立即可見)

繼續(xù)我們上面的緩存一致性的問題,這個問題,在Java內(nèi)存模型中,就是可見性的問題,即一個線程修改了共享變量的值,對另一個線程來說是不是立即可見的。如果不是立即可見的,那么就會出現(xiàn)緩存一致性的問題,如果是立即可見的,那么另一個線程在進行操作的時候,拿到的變量值就是新的。就可以解決可見性的問題。

那么怎么解決可見性問題呢?

  • 方案一:加鎖

將共享變量加鎖,無論是synchronized還是Lock都可以,加鎖達到的目的是在同一時間內(nèi)只能有一個線程能對共享變量進行操作,就是說,共享變量從讀取到工作內(nèi)存到更新值后,同步回主內(nèi)存的過程中,其他線程是操作不了這個變量的。這樣自然就解決了可見性的問題了,但是這樣的效率比較低,操作不了共享變量的線程就只能阻塞。

  • 方案二:volatile修飾修飾共享變量

當(dāng)一個共享變量被volatile修飾后,會保證每個線程將變量修改后的值立即同步回主內(nèi)存中,當(dāng)其他線程有需要讀取變量時會讀取到新的變量值。

那么volatile做了些什么操作就能解決可見性的問題呢?

被volatile修飾的變量,在被線程操作時,會有這樣的機制:

就是線程對變量操作時會從主內(nèi)存中讀取到自己的工作內(nèi)存中,當(dāng)線程對變量進行了修改后,那么其他已經(jīng)讀取了此變量的線程中的變量副本就會失效,這樣其他線程在使用變量的時候,發(fā)現(xiàn)已經(jīng)失效,那么就會去主內(nèi)存中重新獲取,這樣獲取到的就只新的值了。

那么volatile這個關(guān)鍵字是如何實現(xiàn)這套機制的呢?

因為一臺計算機有多臺CPU,同一個變量,在多個CPU中緩存的值有可能不一樣,那么以誰緩存的值為準呢?

既然大家都有自己的值,那么各個CPU間就產(chǎn)生了一種協(xié)議,來保證按照一定的規(guī)律為準,來確定共享變量的準確值,這樣各個CPU在讀寫共享變量時都按照協(xié)議來操作。

這就是緩存一致性協(xié)議。

最著名的緩存一致性協(xié)議就是Intel的MESI了,說MESI時,先解釋一下,緩存行:

緩存行(cache line):CPU高速緩存的中可以分配的最小存儲單位,高速緩存中的變量都是存在緩存行中的。

MESI的核心思想就是,當(dāng)CPU對變量進行寫操作時發(fā)現(xiàn),變量是共享變量,那么就會通知其他CPU中將該變量的緩存行設(shè)置為無效狀態(tài)。當(dāng)其他CPU在操作變量時發(fā)現(xiàn)此變量在的緩存行已經(jīng)無效,那么就會去主內(nèi)存中重新讀取新的變量。

那么其他CPU是如何發(fā)現(xiàn)變量被修改了的呢?

因為CPU和其他部件的進行通信是通過總線來進行的,所以每個CPU通過嗅探總線上的傳播數(shù)據(jù),來檢查自己緩存的值是不是過期了,當(dāng)處理器發(fā)現(xiàn)自己換成行對應(yīng)的內(nèi)存地址被修改后,就會將自己工作內(nèi)存中的緩存行設(shè)置成無須狀態(tài),當(dāng)CPU對此變量進行修改時會重新從系統(tǒng)主內(nèi)存中讀取變量。

深入淺析Java中的volatile

Volatile的有序性(禁止指令重排)

一般來說,我們寫程序的時候,都是要把先代碼從上往下寫,默認的認為程序是自頂向下順序執(zhí)行的,但是CPU為了提高效率,在保證最終結(jié)果準確的情況下,是會對指令進行重新排序的。就是說寫在前的代碼不一定先執(zhí)行,在后面的也不一定晚執(zhí)行。

舉個例子:

int a = 5; // 代碼1
int b = 8; // 代碼2
a = a + 4;	// 代碼3
int c = a + b;	// 代碼4

網(wǎng)站欄目:深入淺析Java中的volatile-創(chuàng)新互聯(lián)
網(wǎng)頁網(wǎng)址:http://www.chinadenli.net/article2/djdpic.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版響應(yīng)式網(wǎng)站搜索引擎優(yōu)化商城網(wǎng)站網(wǎng)站設(shè)計虛擬主機

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站建設(shè)