第六章 塊與大中樞派發(fā)—第45條:使用dispatch_once來執(zhí)行只需運行一次的線程安全代碼

單例模式(singleton)對Objective-C開發(fā)者來說并不陌生瓷患,常見的實現(xiàn)方式為: 在類中編寫名為sharedInstance的方法,該方法只會返回全類共用的單例實例,而不會在每次調(diào)用時都創(chuàng)建新的實例末购。假設有個類叫做EOCClass,那么這個共享實例的方法一般都會這樣寫:

@implementation EOCClass

+ (id)sharedInstance
{
    static EOCClass *sharedInstance = nil;
    @synchronized (self) {
        if (!sharedInstance) {
            sharedInstance = [[self alloc] init];
        }
    }
    return sharedInstance;
}

@end

線程安全是爭論的主要問題。為保證線程安全佩迟,上述代碼將創(chuàng)建單例實例的代碼包裹在同步塊里团滥。無論是好是壞,反正這種實現(xiàn)方式很常用报强。
不過GCD引入了一項特性灸姊,能使單例實現(xiàn)起來更為容易。所用的函數(shù)是:

void dispatch_once(dispatch_once_t *token,
                                   dispatch_block_t block);

此函數(shù)接受類型為dispatch_once_t的特殊參數(shù)躺涝,筆者稱其為"標記"(token)厨钻,此外還接受塊參數(shù)。對于給定的標記來說坚嗜,該函數(shù)保證相關的塊必定會執(zhí)行夯膀,且僅執(zhí)行一次。首次調(diào)用該函數(shù)時苍蔬,必然會執(zhí)行塊中的代碼诱建,最重要的一點在于,此操作完全是線程安全的碟绑。對于只需執(zhí)行一次的塊來說俺猿,每次調(diào)用函數(shù)時傳入的標記都必須完全相同。因此格仲,開發(fā)者通常將標記變量聲明在static或global作用域里押袍。

剛才實現(xiàn)單例模式所用的sharedInstance方法,可以用此函數(shù)來改寫:

+ (id)sharedInstance {
    static EOCClass *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

使用dispatch_once可以簡化代碼并且徹底保證線程安全凯肋,開發(fā)者根本無須擔心加鎖或同步谊惭。所有問題都由GCD在底層處理。由于每次調(diào)用時都必須使用完全相同的標記侮东,所以標記要聲明成static圈盔。把該變量定義在static作用域中,可以保證編譯器在每次執(zhí)行sharedInstance方法時都會復用這個變量悄雅,而不會創(chuàng)建新變量驱敲。
此外,dispatch_once更高效宽闲。它沒有使用重量級的同步機制众眨,若是那樣做的話,每次運行代碼前都要獲取鎖容诬,相反围辙,此函數(shù)采用"原子訪問"(atomic access)來查詢標記,以判斷其所對應的代碼原來是否已經(jīng)執(zhí)行過放案。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市矫俺,隨后出現(xiàn)的幾起案子吱殉,更是在濱河造成了極大的恐慌掸冤,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件友雳,死亡現(xiàn)場離奇詭異稿湿,居然都是意外死亡,警方通過查閱死者的電腦和手機押赊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門饺藤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人流礁,你說我怎么就攤上這事涕俗。” “怎么了神帅?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵再姑,是天一觀的道長。 經(jīng)常有香客問我找御,道長元镀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任霎桅,我火速辦了婚禮栖疑,結果婚禮上,老公的妹妹穿的比我還像新娘滔驶。我一直安慰自己遇革,他們只是感情好,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布瓜浸。 她就那樣靜靜地躺著澳淑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪插佛。 梳的紋絲不亂的頭發(fā)上杠巡,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天,我揣著相機與錄音雇寇,去河邊找鬼氢拥。 笑死,一個胖子當著我的面吹牛锨侯,可吹牛的內(nèi)容都是我干的嫩海。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼囚痴,長吁一口氣:“原來是場噩夢啊……” “哼叁怪!你這毒婦竟也來了?” 一聲冷哼從身側響起深滚,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤奕谭,失蹤者是張志新(化名)和其女友劉穎涣觉,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體血柳,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡官册,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了难捌。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膝宁。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖根吁,靈堂內(nèi)的尸體忽然破棺而出员淫,到底是詐尸還是另有隱情,我是刑警寧澤婴栽,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布满粗,位于F島的核電站,受9級特大地震影響愚争,放射性物質(zhì)發(fā)生泄漏映皆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一轰枝、第九天 我趴在偏房一處隱蔽的房頂上張望捅彻。 院中可真熱鬧,春花似錦鞍陨、人聲如沸步淹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缭裆。三九已至,卻和暖如春寿烟,著一層夾襖步出監(jiān)牢的瞬間澈驼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工筛武, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留缝其,地道東北人。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓徘六,卻偏偏與公主長得像内边,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子待锈,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容