日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
Java的synchronized 能防止指令重排序嗎?

引言

「二狗」:二胖你昨天請(qǐng)假了是不是又去面試了啊?

「二胖」:別說(shuō)了我就出去試試水,看看現(xiàn)在工作好不好找,順帶出去找找打擊,然后才能好好靜下心來(lái)好好學(xué)習(xí)。

「二狗:」 那被打擊的怎么樣啊?知道自己是什么樣的水平了吧,壞笑。

「二胖」:基礎(chǔ)太差,一面就讓回去等通知了,我要好好學(xué)習(xí)了,不跟你瞎扯了。

「二狗:」 都問(wèn)了你什么問(wèn)題啊,把你打擊成這樣?一起復(fù)盤(pán)下讓我也好好準(zhǔn)備下啊。

「二胖」:好吧,你既然這么好奇,那我就大概說(shuō)下吧,你搬上小板凳仔細(xì)挺好了哦。我要開(kāi)始我的表演了。

下面二胖第一面開(kāi)始了。

「面試官」:二胖是吧,先做個(gè)自我介紹吧。

「二胖」:好的,我叫二胖,我來(lái)自長(zhǎng)沙,今年25歲,從事java開(kāi)發(fā)快3年了,現(xiàn)在在XX公司XX事業(yè)部擔(dān)任高級(jí)「java」開(kāi)發(fā)工程師,主要負(fù)責(zé)XX系統(tǒng)。。。。。

「面試官」:好的,我看你簡(jiǎn)歷上寫(xiě)著熟練掌握并發(fā)編程你能跟我說(shuō)說(shuō)并發(fā)編程里面你都知道哪些關(guān)鍵字。

「二胖:」 這不就是要考我 synchronized 和volatile 這個(gè)我擅長(zhǎng)啊,我特意背過(guò)的,synchronized 是java提供的一個(gè)關(guān)鍵字它主要能保證原子性、有序性它的底層主要是通過(guò)Monitor來(lái)實(shí)現(xiàn)的。volatile也是java的一個(gè)關(guān)鍵字它的主要作用是可以保證可見(jiàn)性。。。。此處省略1000字。

「面試官」:八股文背的不錯(cuò),說(shuō)了這么多,我們來(lái)動(dòng)手試試吧,寫(xiě)一個(gè)雙重校驗(yàn)鎖(dcl)的單例我看看。

「二胖:」 從屁股口袋里拿出了筆三下五除二就把它默寫(xiě)出來(lái)了。

「面試官」:你有說(shuō)道volatile關(guān)鍵字和synchronized關(guān)鍵字。synchronized可以保證原子性、有序性和可見(jiàn)性。而volatile卻只能保證有序性和可見(jiàn)性。那么,我們?cè)賮?lái)看一下雙重校驗(yàn)鎖實(shí)現(xiàn)的單例,已經(jīng)使用了synchronized,為什么還需要volatile?這個(gè)volatile是否可以去掉?

「二胖:」 讓我想想,貌似好像確實(shí)可以去掉。

「面試官:」 我們今天的面試就到這里吧,后續(xù)有消息人事會(huì)聯(lián)系你,感謝你今天來(lái)面試。

二胖很郁悶回去谷歌了下這個(gè)問(wèn)題,「stackoverflow」上也有這個(gè)問(wèn)題,看樣子不只我一個(gè)人不知道這個(gè)問(wèn)題嗎?看樣子面試掛的不冤「以上故事純屬虛構(gòu),如有雷同請(qǐng)以本文為主?!?/p>

synchronized 的有序性?

我們先來(lái)看看沒(méi)有加volatile 修飾的單例:

 
 
 
 
  1. public class Singleton {   
  2.     private static Singleton singleton;   
  3.      private Singleton (){}   
  4.      public static Singleton getSingleton() {   
  5.      if (singleton == null) {   
  6.          synchronized (Singleton.class) {   
  7.              if (singleton == null) {   
  8.                  singleton = new Singleton();   
  9.              }   
  10.           }   
  11.       }   
  12.       return singleton;   
  13.       }   
  14.   }   

上述代碼看下來(lái)是不是感覺(jué)沒(méi)啥問(wèn)題。首先我們先來(lái)看下這一行代碼到底干了哪些事情

 
 
 
 
  1. singleton = new Singleton()  

上述過(guò)程我們可以簡(jiǎn)化成3個(gè)步驟:

①「JVM」為對(duì)象分配一塊內(nèi)存M。

②在內(nèi)存M上為對(duì)象進(jìn)行初始化。

③將內(nèi)存M的地址復(fù)制給singleton變量。

這個(gè)步驟有兩種執(zhí)行順序可以按照 「①②③」或者「①③②」來(lái)執(zhí)行。當(dāng)我們按照「①③②」的順序來(lái)執(zhí)行的時(shí)候 我們假設(shè)有兩個(gè)線(xiàn)程ThreadA 和ThreadB 同時(shí)來(lái)請(qǐng)求Singleton.getSingleton方法:

正常情況按照 「①②③」的順序來(lái)執(zhí)行

「第一步:」ThreadA 進(jìn)入到第8行,執(zhí)行 singleton = new Singleton() 進(jìn)行對(duì)象的初始化(按照對(duì)象初始化的過(guò)程 「①②③」)執(zhí)行完。

「第二步:」 ThreadB進(jìn)入第5行判斷singleton不為空(第一步已經(jīng)初始化好了),直接返回singleton**第三步:**拿到這個(gè)對(duì)象做其他的操作。這樣看下來(lái)是不是沒(méi)有啥問(wèn)題。

那如果對(duì)象初始化的時(shí)候按照 「①③②」 的步驟我們?cè)賮?lái)看看:「第一步:」 ThreadA進(jìn)入到第8行,執(zhí)行 singleton = new Singleton() 執(zhí)行完.①JVM為對(duì)象分配一塊內(nèi)存M。③將內(nèi)存的地址復(fù)制給singleton變量。

「第二步:」 此時(shí)ThreadB直接進(jìn)入第5行,發(fā)現(xiàn)singleton已經(jīng)不為空了然后直接就跳轉(zhuǎn)到12行拿到這個(gè)singleton返回去執(zhí)行操作去了。此時(shí)ThreadB拿到的singleton對(duì)象是個(gè)半成品對(duì)象,因?yàn)檫€沒(méi)有為這個(gè)對(duì)象進(jìn)行初始化(「②還沒(méi)執(zhí)行」)?!傅谌剑骸?所以ThreadB拿到的對(duì)象去執(zhí)行方法可能會(huì)有異常產(chǎn)生。至于為什么會(huì)這樣列?《Java 并發(fā)編程實(shí)戰(zhàn)》有提到

有 synchronized 無(wú) volatile 的 DCL(雙重檢查鎖) 會(huì)出現(xiàn)的情況:線(xiàn)程可能看到引用的當(dāng)前值,但對(duì)象的狀態(tài)值確少失效的,這意味著線(xiàn)程可以看到對(duì)象處于無(wú)效或錯(cuò)誤的狀態(tài)。

說(shuō)白了也就是ThreadB是可以拿到一個(gè)引用已經(jīng)有了但是內(nèi)存資源還沒(méi)有分配的對(duì)象。如果要解決創(chuàng)建對(duì)象按照①②③的順序,其實(shí)也就是為了解決指令重排只要第2行加個(gè)volatile修飾就好。

「說(shuō)好的synchronized 不是可以保證有序性的嗎?volatile的有序性?synchronized 不能不夠保證指令重排嗎?」

怎么來(lái)定義順序呢?《深入理解Java虛擬機(jī)第三版》有提到

Java程序中天然的有序性可以總結(jié)為一句話(huà):如果在本線(xiàn)程內(nèi)觀(guān)察,所有操作都是天然有序的。如果在一個(gè)線(xiàn)程中觀(guān)察另一個(gè)線(xiàn)程,所有操作都是無(wú)序的。前半句是指“線(xiàn)程內(nèi)似表現(xiàn)為串行的語(yǔ)義”,后半句是指“指令重排”現(xiàn)象和“工作內(nèi)存與主內(nèi)存同步延遲”現(xiàn)象。

  • 「synchronized」 的有序性是持有相同鎖的兩個(gè)同步塊只能串行的進(jìn)入,即被加鎖的內(nèi)容要按照順序被多個(gè)線(xiàn)程執(zhí)行,但是其內(nèi)部的同步代碼還是會(huì)發(fā)生重排序,使塊與塊之間有序可見(jiàn)。
  • 「volatile」的有序性是通過(guò)插入內(nèi)存屏障來(lái)保證指令按照順序執(zhí)行。不會(huì)存在后面的指令跑到前面的指令之前來(lái)執(zhí)行。是保證編譯器優(yōu)化的時(shí)候不會(huì)讓指令亂序。
  • 「synchronized 是不能保證指令重排的」。

結(jié)束

由于自己才疏學(xué)淺,難免會(huì)有紕漏,假如你發(fā)現(xiàn)了錯(cuò)誤的地方,還望留言給我指出來(lái),我會(huì)對(duì)其加以修正。

本文轉(zhuǎn)載自微信公眾號(hào)「 java金融」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系 java金融公眾號(hào)。


網(wǎng)頁(yè)標(biāo)題:Java的synchronized 能防止指令重排序嗎?
文章分享:http://m.5511xx.com/article/dpdhiij.html