<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Jhonney的專欄

       ----人見人愛
    隨筆 - 49, 文章 - 1, 評論 - 23, 引用 - 0
    數據加載中……

    單例的雙檢鎖

     

    前幾天在看一段.NET源代碼的時候偶爾遇到了Double-checked Locking (雙檢鎖)的一個使用,于是想到了以前看過的一些資料,寫出來分享一下。

    主要參考:The "Double-Checked Locking is Broken" Delaration (http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html)

    雙檢鎖是在多線程環境下很常見的一種實現singleton模式里lazy initialization的方法。

    先看一下最這個模式的起源(注:代碼為Java,不過這個問題適用各種語言,比如C++):

    // Single threaded version
    class Foo {
    private Helper helper = null;
    public Helper getHelper() {
    if (helper == null)
    helper
    = new Helper();
    return helper;
    }
    // other functions and members...
    }

    很容易看出,

    在多線程的情況下,上面的getHelper是不能正確工作的(可能生成多個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...
    }

    這樣寫程序不會出錯,因為整個getHelper是一個整體的"critical section",但就是效率很不好,因為我們的目的其實只是在第一個初始化helper的時候需要locking(加鎖),而后面取用helper的時候,根本不需要線程同步。

    于是聰明的人們想出了下面的做法:

    // Broken multithreaded version
    // "Double-Checked Locking" idiom
    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),因為第一種方法看起來更自然。

    在上面的參考文章中還提到了更復雜的修改方法,不過很可惜,都是錯誤的,我這里就略去不介紹了。

    那么有什么解決方案呢?有如下一些:

    1. 如果你的singleton是static的,那你可以將這個singleton申明為一個獨立類的一個成員變量:

    class HelperSingleton {
    static Helper singleton = new Helper();
    }

    Java的語意會保證:1. lazy initialization, 2. singleton在被調用前已經完全初始化了。

    2. 雙檢鎖對于基礎類型(比如int)適用。很顯然吧,因為基礎類型沒有調用構造函數這一步。事實上,我前面提到的.NET里面的那段代碼就是在一個int變量上使用雙檢鎖。

    3. 使用explicit memory barrier。這個我不說了,關于memory barrier我們可以寫一本小冊子來介紹,有興趣的朋友可以自己查一下資料,上面的參考里也有很多相關鏈接。

    4. 使用Thread Local Storage。也不介紹了。

    上面的文章還提到了Java在考慮為volatile關鍵字定義新的語意來解決這個問題以及雙檢鎖對Java里immutable對象影響,

    不過因 為這篇文章已經有些年頭而我也不是Java的專家,所以不太清楚現在的情況怎樣,總之,在遇到雙檢鎖的時候,需要的朋友應該做些必要的調查來確定自己的代 碼是線程安全的。

    posted on 2007-04-12 21:53 Jhonney 閱讀(2649) 評論(2)  編輯  收藏

    評論

    # re: 單例的雙檢鎖  回復  更多評論   

    也可以這樣!

    private static Helper helper;
    public static Helper GetHelper()
    {
    //通過“雙檢鎖” 模式支持多線程的應用
    if (balancer==null)
    {
    //只有一個線程可以取得 mutex .
    Mutex mutex = new Mutex();
    mutex.WaitOne();
    if (helper==null)
    {
    helper= new Helper();
    mutex.Close();
    }
    } return helper;
    }
    2011-04-08 15:26 | Tonight

    # re: 單例的雙檢鎖  回復  更多評論   

    把 IF 里面那balancer 改成 helper ,忘了改了!
    2011-04-08 15:27 | Tonight

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 最近免费2019中文字幕大全| 精品国产免费一区二区三区| 国产在线一区二区综合免费视频| 免费国产综合视频在线看| 亚洲日本一线产区和二线| 24小时日本在线www免费的| 67194在线午夜亚洲| 精品久久久久久久免费人妻| 亚洲youwu永久无码精品| 日韩伦理片电影在线免费观看| 亚洲欧美日韩综合久久久久| 暖暖免费高清日本一区二区三区| 性色av极品无码专区亚洲| 日韩免费高清视频| 杨幂最新免费特级毛片| 国产亚洲一区二区三区在线不卡| 国产在线观a免费观看| 亚洲午夜久久影院| 成人免费视频88| 美女露隐私全部免费直播| 国产亚洲精aa成人网站| 久久久免费的精品| 亚洲一卡2卡3卡4卡国产网站| 成人免费福利电影| 一级成人a做片免费| 亚洲AV无码一区二区三区系列| 91精品国产免费久久国语蜜臀| 亚洲色欲啪啪久久WWW综合网| 国产乱色精品成人免费视频| a级毛片黄免费a级毛片| 亚洲日韩在线视频| 日本一道在线日本一道高清不卡免费 | 亚洲AV无码专区国产乱码电影| 222www免费视频| 亚洲av无码成人精品区一本二本| 久久亚洲精品无码观看不卡| 7m凹凸精品分类大全免费| 亚洲av成人一区二区三区观看在线 | 亚洲成a人片在线观看老师| 久久久久久久99精品免费| 亚洲人成自拍网站在线观看|