成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

雙重檢查鎖定失敗可能性

開發(fā) 后端
雙重檢查鎖定在延遲初始化的單例模式中見得比較多(單例模式實(shí)現(xiàn)方式很多,這里為說明雙重檢查鎖定問題,只選取這一種方式).

雙重檢查鎖定在延遲初始化的單例模式中見得比較多(單例模式實(shí)現(xiàn)方式很多,這里為說明雙重檢查鎖定問題,只選取這一種方式),先來看一個(gè)版本:

 

  1. public class Singleton {  
  2.  
  3.     private static Singleton instance = null;  
  4.  
  5.     private Singleton(){}  
  6.  
  7.       
  8.  
  9.     public static Singleton  getInstance() {  
  10.  
  11.        if(instance == null) {  
  12.  
  13.            instance = new Singleton();  
  14.  
  15.        }  
  16.  
  17.        return instance;  
  18.  
  19.     }  
  20.  
  21. }  

 

上面是最原始的模式,一眼就可以看出,在多線程環(huán)境下,可能會(huì)產(chǎn)生多個(gè)Singleton實(shí)例,于是有了其同步的版本:

 

  1. public class Singleton {  
  2.  
  3.     private static Singleton instance = null;  
  4.  
  5.     private Singleton(){}  
  6.  
  7.       
  8.  
  9.     public synchronized static Singleton getInstance() {  
  10.  
  11.        if(instance == null) {  
  12.  
  13.            instance = new Singleton();  
  14.  
  15.        }  
  16.  
  17.        return instance;  
  18.  
  19.     }  
  20.  
  21. }  

 

在這個(gè)版本中,每次調(diào)用getInstance都需要取得Singleton.class上的鎖,然而該鎖只是在開始構(gòu)建Singleton 對(duì)象的時(shí)候才是必要的,后續(xù)的多線程訪問,效率會(huì)降低,于是有了接下來的版本:

 

  1. public class Singleton {  
  2.  
  3.     private static Singleton instance = null;  
  4.  
  5.     private Singleton(){}  
  6.  
  7.       
  8.  
  9.     public static Singleton getInstance() {  
  10.  
  11.        if(instance == null) {  
  12.  
  13.            synchronized(Singleton.class) {  
  14.  
  15.               if(instance == null) {  
  16.  
  17.                   instance = new Singleton();  
  18.  
  19.               }  
  20.  
  21.            }  
  22.  
  23.        }  
  24.  
  25.        return instance;  
  26.  
  27.     }  
  28.  
  29. }  

 

很好的想法!不幸的是,該方案也未能解決問題之根本:

原因在于:初始化Singleton 和 將對(duì)象地址寫到instance字段 的順序是不確定的。在某個(gè)線程new Singleton()時(shí),在構(gòu)造方法被調(diào)用之前,就為該對(duì)象分配了內(nèi)存空間并將對(duì)象的字段設(shè)置為默認(rèn)值。此時(shí)就可以將分配的內(nèi)存地址賦值給instance字段了,然而該對(duì)象可能還沒有初始化;此時(shí)若另外一個(gè)線程來調(diào)用getInstance,取到的就是狀態(tài)不正確的對(duì)象。

鑒于以上原因,有人可能提出下列解決方案:

 

  1. public class Singleton {  
  2.  
  3.     private static Singleton instance = null;  
  4.  
  5.     private Singleton(){}  
  6.  
  7.       
  8.  
  9.     public static Singleton getInstance() {  
  10.  
  11.        if(instance == null) {  
  12.  
  13.            Singleton temp;  
  14.  
  15.            synchronized(Singleton.class) {  
  16.  
  17.               temp = instance;  
  18.  
  19.               if(temp == null) {  
  20.  
  21.                   synchronized(Singleton.class) {  
  22.  
  23.                      temp = new Singleton();  
  24.  
  25.                   }  
  26.  
  27.                   instance = temp;  
  28.  
  29.               }  
  30.  
  31.            }  
  32.  
  33.        }  
  34.  
  35.        return instance;  
  36.  
  37.     }  
  38.  
  39. }  

 

該方案將Singleton對(duì)象的構(gòu)造置于最里面的同步塊,這種思想是在退出該同步塊時(shí)設(shè)置一個(gè)內(nèi)存屏障,以阻止初始化Singleton 和 將對(duì)象地址寫到instance字段 的重新排序。

不幸的是,這種想法也是錯(cuò)誤的,同步的規(guī)則不是這樣的。退出監(jiān)視器(退出同步)的規(guī)則是:所以在退出監(jiān)視器前面的動(dòng)作都必須在釋放監(jiān)視器之前完成。然而,并沒有規(guī)定說退出監(jiān)視器之后的動(dòng)作不能放到退出監(jiān)視器之前完成。也就是說同步塊里的代碼必須在退出同步時(shí)完成,而同步塊后面的代碼則可以被編譯器或運(yùn)行時(shí)環(huán)境移到同步塊中執(zhí)行。

編譯器可以合法的,也是合理的,將instance = temp移動(dòng)到最里層的同步塊內(nèi),這樣就出現(xiàn)了上個(gè)版本同樣的問題。

在JDK1.5及其后續(xù)版本中,擴(kuò)充了volatile語義,系統(tǒng)將不允許對(duì) 寫入一個(gè)volatile變量的操作與其之前的任何讀寫操作 重新排序,也不允許將 讀取一個(gè)volatile變量的操作與其之后的任何讀寫操作 重新排序。

在jdk1.5及其后的版本中,可以將instance 設(shè)置成volatile以讓雙重檢查鎖定生效,如下:

 

  1. public class Singleton {  
  2.  
  3.     private static volatile Singleton instance = null;  
  4.  
  5.     private Singleton(){}  
  6.  
  7.       
  8.  
  9.     public static Singleton getInstance() {  
  10.  
  11.        if(instance == null) {  
  12.  
  13.            synchronized(Singleton.class) {  
  14.  
  15.               if(instance == null) {  
  16.  
  17.                   instance = new Singleton();  
  18.  
  19.               }  
  20.  
  21.            }  
  22.  
  23.        }  
  24.  
  25.        return instance;  
  26.  
  27.     }  
  28.  
  29. }  

 

需要注意的是:在JDK1.4以及之前的版本中,該方式仍然有問題。

【編輯推薦】

  1. 有趣的Java對(duì)象序列化緩存問題
  2. 關(guān)于Java對(duì)象序列化您不知道的5件事
  3. Java 7 I/O新功能探秘:同步操作,多播與隨機(jī)存取
  4. Java實(shí)用技巧:當(dāng)不能拋出checked異常時(shí)
  5. 多線程開發(fā)的捷徑:構(gòu)建Java并發(fā)模型框架
責(zé)任編輯:金賀 來源: ITEYE博客
相關(guān)推薦

2022-12-30 07:40:12

DeepKitTypeScript靜態(tài)類型

2016-11-11 00:33:25

雙重檢查鎖定延遲初始化線程

2018-03-02 11:38:11

2013-11-29 09:51:26

C++雙重檢查鎖定

2013-12-23 09:48:43

C++鎖定模式

2012-06-04 13:28:51

AndroidChrome OS

2017-07-21 16:40:29

網(wǎng)易云場(chǎng)景專屬云

2011-04-18 13:43:42

2023-10-27 14:25:26

組件庫無限可能性

2016-09-21 09:16:55

Qlik

2021-02-20 12:04:51

比特幣區(qū)塊鏈美元

2020-05-15 13:42:03

物聯(lián)網(wǎng)人工智能軍事物聯(lián)網(wǎng)

2013-03-19 11:13:14

Google廣告SXSW

2019-04-22 08:57:46

硅谷996ICU

2020-08-11 09:38:40

微信蘋果美國

2009-03-11 18:27:04

Windows 7商業(yè)版

2011-04-18 13:47:59

ECC私鑰

2019-04-15 10:30:38

程序員技能開發(fā)者

2018-11-26 09:48:57

服務(wù)器異常宕機(jī)

2009-05-21 16:08:56

谷歌演算程序員工離職
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 国产精品一区在线 | 国产精品视频不卡 | 国产高清在线精品 | 国产一区二区在线免费观看 | 黄色片av | 拍戏被cao翻了h承欢 | 日本爱爱视频 | 视频一区在线观看 | 久久精品亚洲 | 亚洲日本欧美 | 国产偷自视频区视频 | 日干夜操 | 欧美日韩1区2区3区 欧美久久一区 | 911网站大全在线观看 | 最新中文字幕在线 | 中文字幕一区二区三区在线乱码 | 国产精品美女一区二区三区 | 国产色 | 男人av在线 | 午夜精品一区二区三区在线观看 | 亚洲国产精品一区二区三区 | 国产黄色在线观看 | 成人一级黄色毛片 | 精精国产xxxx视频在线播放7 | 国产乱肥老妇国产一区二 | 免费一级网站 | 久久精品国产久精国产 | 在线欧美视频 | 国产目拍亚洲精品99久久精品 | 国产精品区一区二区三 | 国内精品一区二区三区 | 久久伊人影院 | 99精品国自产在线观看 | av一二三区 | 久久综合激情 | 天天拍天天操 | 久久6| 欧美人妇做爰xxxⅹ性高电影 | jizz在线免费观看 | 中文字幕视频免费 | 中文字幕av在线播放 |