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

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

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

    Jhonney的專欄

       ----人見(jiàn)人愛(ài)
    隨筆 - 49, 文章 - 1, 評(píng)論 - 23, 引用 - 0
    數(shù)據(jù)加載中……

    單例的雙檢鎖

     

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

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

    雙檢鎖是在多線程環(huán)境下很常見(jiàn)的一種實(shí)現(xiàn)singleton模式里lazy initialization的方法。

    先看一下最這個(gè)模式的起源(注:代碼為Java,不過(guò)這個(gè)問(wèn)題適用各種語(yǔ)言,比如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是不能正確工作的(可能生成多個(gè)helper實(shí)體)。

     

    于是有下面的改進(jìn)代碼:

    // 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...
    }

    這樣寫(xiě)程序不會(huì)出錯(cuò),因?yàn)檎麄€(gè)getHelper是一個(gè)整體的"critical section",但就是效率很不好,因?yàn)槲覀兊哪康钠鋵?shí)只是在第一個(gè)初始化helper的時(shí)候需要locking(加鎖),而后面取用helper的時(shí)候,根本不需要線程同步。

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

    // 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...
    }

    思路很簡(jiǎn)單,就是我們只需要同步(synchronize)初始化helper的那部分代碼從而使代碼既正確又很有效率。

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

    很可惜,這樣的寫(xiě)法在很多平臺(tái)和優(yōu)化編譯器上是錯(cuò)誤的。

    原因在于:helper = new Helper()這行代碼在不同編譯器上的行為是無(wú)法預(yù)知的。一個(gè)優(yōu)化編譯器可以合法地如下實(shí)現(xiàn)helper = new Helper():

    1. helper = 給新的實(shí)體分配內(nèi)存

    2. 調(diào)用helper的構(gòu)造函數(shù)來(lái)初始化helper的成員變量

    現(xiàn)在想象一下有線程A和B在調(diào)用getHelper,

    線程A先進(jìn)入,在執(zhí)行到步驟1的時(shí)候被踢出了cpu。然后線程B進(jìn)入,B看到的是helper 已經(jīng)不是null了(內(nèi)存已經(jīng)分配),于是它開(kāi)始放心地使用helper,但這個(gè)是錯(cuò)誤的,因?yàn)樵谶@一時(shí)刻,helper的成員變量還都是缺省值,A還沒(méi) 有來(lái)得及執(zhí)行步驟2來(lái)完成helper的初始化。

     

    當(dāng)然編譯器也可以這樣實(shí)現(xiàn):

    1. temp = 分配內(nèi)存

    2. 調(diào)用temp的構(gòu)造函數(shù)

    3. helper = temp

    如果編譯器的行為是這樣的話我們似乎就沒(méi)有問(wèn)題了,但事實(shí)卻不是那么簡(jiǎn)單,因?yàn)槲覀儫o(wú)法知道某個(gè)編譯器具體是怎么做的,因?yàn)樵贘ava的 memory model里對(duì)這個(gè)問(wèn)題沒(méi)有定義(C++也一樣),而事實(shí)上有很多編譯器都是用第一種方法(比如symantec的just-in-time compiler),因?yàn)榈谝环N方法看起來(lái)更自然。

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

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

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

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

    Java的語(yǔ)意會(huì)保證:1. lazy initialization, 2. singleton在被調(diào)用前已經(jīng)完全初始化了。

    2. 雙檢鎖對(duì)于基礎(chǔ)類型(比如int)適用。很顯然吧,因?yàn)榛A(chǔ)類型沒(méi)有調(diào)用構(gòu)造函數(shù)這一步。事實(shí)上,我前面提到的.NET里面的那段代碼就是在一個(gè)int變量上使用雙檢鎖。

    3. 使用explicit memory barrier。這個(gè)我不說(shuō)了,關(guān)于memory barrier我們可以寫(xiě)一本小冊(cè)子來(lái)介紹,有興趣的朋友可以自己查一下資料,上面的參考里也有很多相關(guān)鏈接。

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

    上面的文章還提到了Java在考慮為volatile關(guān)鍵字定義新的語(yǔ)意來(lái)解決這個(gè)問(wèn)題以及雙檢鎖對(duì)Java里immutable對(duì)象影響,

    不過(guò)因 為這篇文章已經(jīng)有些年頭而我也不是Java的專家,所以不太清楚現(xiàn)在的情況怎樣,總之,在遇到雙檢鎖的時(shí)候,需要的朋友應(yīng)該做些必要的調(diào)查來(lái)確定自己的代 碼是線程安全的。

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

    評(píng)論

    # re: 單例的雙檢鎖  回復(fù)  更多評(píng)論   

    也可以這樣!

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

    # re: 單例的雙檢鎖  回復(fù)  更多評(píng)論   

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

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 久9久9精品免费观看| 亚洲国产精品lv| 亚洲欧美成人综合久久久| 免费国产污网站在线观看不要卡| 爽爽爽爽爽爽爽成人免费观看| 青青青国产在线观看免费 | 国产h视频在线观看网站免费| 在线jyzzjyzz免费视频| 情人伊人久久综合亚洲| 亚洲精品天堂成人片AV在线播放| 99精品视频免费| 亚洲av永久无码精品表情包| 亚洲欧美国产国产一区二区三区| 青青草原1769久久免费播放| 国产午夜无码视频免费网站 | 亚洲JIZZJIZZ中国少妇中文| 亚洲综合网美国十次| 国产精品成人亚洲| 日本一区二区三区日本免费| 亚洲日本va午夜中文字幕一区| 青青免费在线视频| 伊人婷婷综合缴情亚洲五月| 亚洲午夜精品一区二区麻豆| 久久国产免费观看精品3| 久久久青草青青国产亚洲免观| 亚洲AV无码专区在线观看成人| 最近2019中文字幕免费大全5| 77777亚洲午夜久久多人| 国产成人+综合亚洲+天堂| 永久免费AV无码国产网站| 亚洲s色大片在线观看| 大片免费观看92在线视频线视频| 大学生美女毛片免费视频| 亚洲天堂电影在线观看| 华人在线精品免费观看| 亚洲日韩中文在线精品第一 | 在线观看亚洲成人| 91精品国产免费久久国语麻豆| 亚洲精品午夜国产VA久久成人| 曰批全过程免费视频免费看| 国产乱子伦精品免费女|