亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢(xún)客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

JAVA并發(fā)編程之驗(yàn)證volatile指令重排-理論篇

Java并發(fā)包下的類(lèi)中大量使用了volatile關(guān)鍵字。通過(guò)之前文章介紹,大家已經(jīng)知道了volatile的三大特性:共享變量可見(jiàn)性;不保證原子性;禁止指令重排后順序性。通過(guò)前面兩篇文章我們通過(guò)代碼驗(yàn)證了前兩個(gè)特性,本文我們就來(lái)驗(yàn)證禁止指令重排保證順序性。

指令重排序的生活例子

去餐廳吃飯預(yù)定位置的的時(shí)候。假設(shè)要去A餐廳吃飯,A餐廳有前臺(tái)B、服務(wù)員C以及老板D。如果就只有你一個(gè)人去吃飯的時(shí)候,你給前臺(tái)或者給服務(wù)器或者給老板說(shuō)一聲把2號(hào)桌預(yù)定了,半小時(shí)后過(guò)來(lái)。餐廳在為了2小時(shí)內(nèi)就你一個(gè)人去吃飯。那么OK,沒(méi)問(wèn)題,別說(shuō)等半個(gè)小時(shí),就是等一個(gè)小時(shí),2號(hào)桌還是你的。

但是,如果現(xiàn)在是吃飯高峰期,很多人來(lái)吃飯,你給前臺(tái)說(shuō)了,前臺(tái)忙著沒(méi)有及時(shí)給服務(wù)員或者沒(méi)有給老板說(shuō),這個(gè)時(shí)候有個(gè)路人甲來(lái)吃飯,剛好看到2號(hào)桌沒(méi)人,老板或者服務(wù)員就讓他就坐2號(hào)桌吃飯了。那么,等你過(guò)來(lái)的時(shí)候,2號(hào)桌已經(jīng)有人了。這個(gè)時(shí)候?qū)τ谀銇?lái)說(shuō),這個(gè)結(jié)果就不是你想要的了。

上面案例,如果從計(jì)算機(jī)執(zhí)行指令角度來(lái)分析的話,你要到2號(hào)桌吃飯,這是預(yù)期結(jié)果。餐廳A就相當(dāng)于是處理器,前臺(tái)B就相當(dāng)于是編譯器,服務(wù)員C和老板D就是指令和內(nèi)存系統(tǒng)。如果你預(yù)定的時(shí)間點(diǎn)不是吃飯高峰期或者沒(méi)有人去餐廳A吃飯。那么你就相當(dāng)于是一個(gè)線程。就是單線程的。老板、前臺(tái)、服務(wù)員怎么安排都可以。因?yàn)橹挥心阋粋€(gè)2號(hào)桌肯定是你的。這是單線程情況下。預(yù)期結(jié)果與實(shí)際結(jié)果就是一致的。

如果你預(yù)定的時(shí)間點(diǎn)是吃飯高峰期,很多人來(lái)吃飯(很多線程),這個(gè)時(shí)候?yàn)榱瞬蛷d效益,無(wú)論是前臺(tái)還是服務(wù)員或者是老板都會(huì)對(duì)你的位置進(jìn)行重排序。在你沒(méi)有來(lái)的時(shí)候,會(huì)安排其他人到你預(yù)定的位置吃飯。如果其他人在你的位置吃飯,這個(gè)時(shí)候你再來(lái)吃飯,那么實(shí)際結(jié)果和預(yù)期結(jié)果就不一樣了。這個(gè)時(shí)候餐廳應(yīng)該做出相應(yīng)的賠償。為了解決這種賠償問(wèn)題,老板就想到了一個(gè)方案。做個(gè)牌子放在客人預(yù)定的桌子上。

當(dāng)前臺(tái)或者是服務(wù)員或者是老板看到餐桌上放的這個(gè)牌子,就知道這個(gè)位置不能再調(diào)動(dòng)了。其中這個(gè)放在餐桌上的牌子就是特殊類(lèi)型的內(nèi)存屏障了。

示意圖如下:

Java并發(fā)編程之驗(yàn)證volatile指令重排-理論篇

 

再來(lái)舉個(gè)更常見(jiàn)的例子:

考試,在考試的時(shí)候老師會(huì)告訴我們,先做會(huì)做的,不會(huì)做的放到后面做。假設(shè)出題老師出題順序是1-5,但是考試會(huì)根據(jù)自己實(shí)際情況做題順序有可能是1、2、4、5、3或者是1、3、4、5、2等等。如果把出題老師看著是寫(xiě)代碼的程序員,題目的順序是代碼一行一行的順序,你的老師會(huì)告訴你先做會(huì)做的,此時(shí)老師就相當(dāng)于是編譯器,會(huì)排序一次。然后你自己做的時(shí)候又會(huì)進(jìn)行重新排序,你自己就相當(dāng)于是處理器又排序了一次。

上面兩個(gè)現(xiàn)實(shí)生活中的案例,我們弄明白后,再來(lái)看看在計(jì)算機(jī)中指令重排問(wèn)題,就很容易理解了。

指令重排

我們程序員編寫(xiě)的代碼在JVM執(zhí)行的時(shí)候,為了提高性能,編譯器和處理器都會(huì)對(duì)代碼編譯后的指令進(jìn)行重排序。分為3種:

1:編譯器優(yōu)化重排:

編譯器的優(yōu)化前提是在保證不改變單線程語(yǔ)義的情況下,對(duì)重新安排語(yǔ)句的執(zhí)行順序。

2:指令并行重排:

如果代碼中某些語(yǔ)句之間不存在數(shù)據(jù)依賴(lài),處理器可以改變語(yǔ)句對(duì)應(yīng)機(jī)器指令的順序

如:int x = 10;int y = 5;對(duì)于這種x y之間沒(méi)有數(shù)據(jù)依賴(lài)關(guān)系的,機(jī)器指令就會(huì)進(jìn)行重新排序。但是對(duì)于:int x = 10; int y = 5; int z = x+y;這種的,因?yàn)閦和x y之間存在數(shù)據(jù)依賴(lài)(z=x+y)關(guān)系。在這種情況下,機(jī)器指令就不會(huì)把z排序在xy前面。

3:內(nèi)存系統(tǒng)的重排序

通過(guò)之前的學(xué)習(xí),我們知道了處理器和主內(nèi)存之間還存在一二三級(jí)緩存。這些讀寫(xiě)緩存的存在,使得程序的加載和存取操作,可能是亂序無(wú)章的。

指令重排序的流程圖

通過(guò)上面介紹,我們可以知道從程序員寫(xiě)的Java源碼到處理器真正實(shí)際執(zhí)行的指令序列,會(huì)經(jīng)歷如下圖的過(guò)程:

 

Java并發(fā)編程之驗(yàn)證volatile指令重排-理論篇

 

執(zhí)行順序:

源碼編譯器優(yōu)化重排序(第一次排序) 指令重排序(第二次)內(nèi)存重排序(第三次) 最終指向的指令。

無(wú)論是第一次編譯器的重排序還是第二、三次的處理器重排序。這些重排序當(dāng)在多線程的場(chǎng)景下可能會(huì)出現(xiàn)線程可見(jiàn)性的問(wèn)題。

如在多線程的情況下,單例模式就不安全了。

為了解決這個(gè)問(wèn)題,JMM允許編譯器在生成指令順序的時(shí)候,可以插入特定類(lèi)型的內(nèi)存屏障來(lái)禁止指令重排序。

當(dāng)一個(gè)變量使用volatile修飾的時(shí)候,volatile關(guān)鍵字就是內(nèi)存屏障。當(dāng)編譯器在生成指令順序的時(shí)候,發(fā)現(xiàn)了volatile,就直接忽略掉。不再重排序了。

示意圖:

Java并發(fā)編程之驗(yàn)證volatile指令重排-理論篇

 

 

分享到:
標(biāo)簽:Java
用戶(hù)無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定