我的java天地

          單例模式的一些版本及演變過程

          @import url(http://www.aygfsteel.com/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css); @import url(http://www.aygfsteel.com/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css); @import url(http://www.aygfsteel.com/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
          版本一:只支持單線程,多線程第一次實例化會有兩個實例生成
          class Foo {
          private Helper helper = null;
          public Helper getHelper() {
          if (helper == null)
          helper
          = new Helper();
          return helper;
          }
          // other functions and members...
          } 版本二:多線程版本:每個線程過來都會到要到synchronized 方法塊,這樣處理效率較低.第一個初始化helper的時候需要locking(加鎖),而后面取用helper的時候,根本不需要線程同步
          // Correct multithreaded version
          class Foo {
          private Helper helper = null;
          public synchronized Helper getHelper() {
          if (helper == null)
          helper
          = new Helper();
          return helper;
          }
          // other functions and members...
          } 版本三:解決每次新建實例都要
          synchronized的問題,運用雙檢鎖來實現.此種方法行不通
          class Foo {
          private Helper helper = null;
          public Helper getHelper() {
          if (helper == null)
          synchronized(
          this) {
          if (helper == null)
          helper
          = new Helper();
          }
          return helper;
          }
          // other functions and members...
          }
          思路很簡單,就是我們只需要同步(synchronize)初始化helper的那部分代碼從而使代碼既正確又很有效率。

          這就是所謂的“雙檢鎖”機制(顧名思義)。

          很可惜,這樣的寫法在很多平臺和優化編譯器上是錯誤的。

          原因在于:helper = new Helper()這行代碼在不同編譯器上的行為是無法預知的。一個優化編譯器可以合法地如下實現helper = new Helper():

          1. helper = 給新的實體分配內存

          2. 調用helper的構造函數來初始化helper的成員變量

          現在想象一下有線程A和B在調用getHelper,線程A先進入,在執行到步驟1的時候被踢出了cpu。然后線程B進入,B看到的是 helper已經不是null了(內存已經分配),于是它開始放心地使用helper,但這個是錯誤的,因為在這一時刻,helper的成員變量還都是缺 省值,A還沒有來得及執行步驟2來完成helper的初始化。

          當然編譯器也可以這樣實現:

          1. temp = 分配內存

          2. 調用temp的構造函數

          3. helper = temp

          如果編譯器的行為是這樣的話我們似乎就沒有問題了,但事實卻不是那么簡單,因為我們無法知道某個編譯器具體是怎么做的,因為在Java的 memory model里對這個問題沒有定義(C++也一樣),而事實上有很多編譯器都是用第一種方法(比如symantec的just-in-time compiler),因為第一種方法看起來更自然。

          在上面的參考文章中還提到了更復雜的修改方法,不過很可惜,都是錯誤的

          關于Out-of-order writes現象,就是
          helper = new Helper();;
          helper已經非空,但對象還沒完成實例化,即new new Helper()未完成
          詳見:
          http://www.ibm.com/developerworks/java/library/j-dcl.html


          版本四:目前知道最后版。實際應用時需驗證一下
          private volatile static Singleton instance;  
            
          public static Singleton getInstance() {  
              if (instance == null) {  
                  synchronized(Singleton.class) {  //1  
                      if (instance == null)          //2  
                          instance = new Singleton();  //3  
                  }  
              }  
              return instance;  
          }  

          因為存在Out-of-order writes現象,所以這里volatile關鍵字是在當instance被初始化給Singleton實例時保證多線程正確地處理instance變量,那這里與線程間的可見性有關嗎?
          我覺得與可見性無關,因為synchronized block已經可以保證塊內變量的可見性,這里應該是變量操作的原子性


          http://en.wikipedia.org/wiki/Double-checked_locking

          posted on 2011-11-21 15:28 tobyxiong 閱讀(240) 評論(0)  編輯  收藏 所屬分類: java

          <2011年11月>
          303112345
          6789101112
          13141516171819
          20212223242526
          27282930123
          45678910

          導航

          統計

          常用鏈接

          留言簿(3)

          隨筆分類(144)

          隨筆檔案(157)

          相冊

          最新隨筆

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 梅河口市| 碌曲县| 甘南县| 海口市| 六枝特区| 兴安盟| 宝鸡市| 贺兰县| 邵阳县| 长汀县| 华容县| 博野县| 瑞安市| 汝城县| 天柱县| 库车县| 阜平县| 五台县| 古交市| 宁晋县| 武隆县| 淳化县| 定安县| 息烽县| 眉山市| 大冶市| 澳门| 日土县| 浪卡子县| 武胜县| 长兴县| 吉木萨尔县| 菏泽市| 怀宁县| 甘肃省| 郎溪县| 清涧县| 香河县| 浦东新区| 高密市| 宜章县|