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

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

新聞中心

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

引言

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

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

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

「二胖」:基礎太差,一面就讓回去等通知了,我要好好學習了,不跟你瞎扯了。

「二狗:」 都問了你什么問題啊,把你打擊成這樣?一起復盤下讓我也好好準備下啊。

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

下面二胖第一面開始了。

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

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

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

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

「面試官」:八股文背的不錯,說了這么多,我們來動手試試吧,寫一個雙重校驗鎖(dcl)的單例我看看。

「二胖:」 從屁股口袋里拿出了筆三下五除二就把它默寫出來了。

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

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

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

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

synchronized 的有序性?

我們先來看看沒有加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.   }   

上述代碼看下來是不是感覺沒啥問題。首先我們先來看下這一行代碼到底干了哪些事情

 
 
 
 
  1. singleton = new Singleton()  

上述過程我們可以簡化成3個步驟:

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

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

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

這個步驟有兩種執(zhí)行順序可以按照 「①②③」或者「①③②」來執(zhí)行。當我們按照「①③②」的順序來執(zhí)行的時候 我們假設有兩個線程ThreadA 和ThreadB 同時來請求Singleton.getSingleton方法:

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

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

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

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

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

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

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

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

怎么來定義順序呢?《深入理解Java虛擬機第三版》有提到

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

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

結(jié)束

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

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


當前題目:Java的synchronized 能防止指令重排序嗎?
分享地址:http://m.5511xx.com/article/dpdhiij.html