iOS_多線程_GCD

本文主要知識點來自:
http://www.reibang.com/p/2d57c72016c6
作者:[行走少年郎]

GCD通過我們的同步異步和串行并發(fā),來決定是否創(chuàng)建新的線程还蹲,(是否實現(xiàn)多線程)。一個線程可以有多個隊列,并且主隊列在主線程所以才特殊嫉戚。尤其要理解新隊列并不一定會產(chǎn)生新的線程锦庸。

首先記錄一下GCD的重要知識點:
任務:同步執(zhí)行(sync)瓣俯,異步執(zhí)行(async)
隊列:串行隊列,并發(fā)隊列鹅颊,主隊列(串行)
創(chuàng)建隊列:

// 串行隊列的創(chuàng)建方法
dispatch_queue_t queue = dispatch_queue_create("name", DISPATCH_QUEUE_SERIAL);
// 并發(fā)隊列的創(chuàng)建方法
dispatch_queue_t queue = dispatch_queue_create("name", DISPATCH_QUEUE_CONCURRENT);
//主隊列獲取方法:
dispatch_queue_t queue = dispatch_get_main_queue();
// 全局并發(fā)隊列的獲取方法
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

任務的創(chuàng)建方法(應該說是將block添加進隊列方法):

// 同步執(zhí)行任務創(chuàng)建方法
dispatch_sync(queue, ^{
   
});
// 異步執(zhí)行任務創(chuàng)建方法
dispatch_async(queue, ^{
   
});

注意同步添加任務到當前線程會造成死鎖,(常見的就是主線程中sync+主隊列:比如我們在a方法里sync添加任務b到主隊列墓造,a方法是主線程執(zhí)行的堪伍,即主線程執(zhí)行a的過程中需要做添加b的操作,但是添加b的操作需要等a執(zhí)行完畢才可以添加觅闽。)
舉個通俗的例子:
假設你(隊列)面前一排便簽(任務)帝雇,你只能看完一個便簽,并且做完上上面寫的東西后才能看后面的便簽(串行執(zhí)行)蛉拙,
這時候第三個便簽上貼了個小標簽(sync添加任務)尸闸。
形成死鎖,小標簽等你做完第三個便簽的事情才能看孕锄,但是不看小標簽就不算做完第三個便簽的事吮廉。
解決辦法:
1用async:將小標簽上的東西寫到新的便簽上,在你執(zhí)行完其他便簽的間隙添加到便簽里面
2使用sync調(diào)用其他隊列:就是第三個便簽上寫著:將下面的小標簽貼到別人的便簽后面畸肆。這時候你不需要看小標簽內(nèi)容也可以完成這個任務宦芦。

GCD常用方法:

1.柵欄方法:dispatch_barrier_async

在執(zhí)行完柵欄前面的操作之后,才執(zhí)行柵欄操作轴脐,最后再執(zhí)行柵欄后邊的操作调卑。

/**
 * 柵欄方法 dispatch_barrier_async
 */
- (void)barrier {
    dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        // 追加任務 1
        [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
        NSLog(@"1---%@",[NSThread currentThread]);      // 打印當前線程
    });
    dispatch_async(queue, ^{
        // 追加任務 2
        [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
        NSLog(@"2---%@",[NSThread currentThread]);      // 打印當前線程
    });
    
    dispatch_barrier_async(queue, ^{
        // 追加任務 barrier
        [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
        NSLog(@"barrier---%@",[NSThread currentThread]);// 打印當前線程
    });
    
    dispatch_async(queue, ^{
        // 追加任務 3
        [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
        NSLog(@"3---%@",[NSThread currentThread]);      // 打印當前線程
    });
    dispatch_async(queue, ^{
        // 追加任務 4
        [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
        NSLog(@"4---%@",[NSThread currentThread]);      // 打印當前線程
    });
}

2.延時執(zhí)行方法:dispatch_after

并不是在指定時間之后才開始執(zhí)行處理,而是在指定時間之后將任務追加到主隊列中大咱。

- (void)after {
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印當前線程
    NSLog(@"asyncMain---begin");
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        // 2.0 秒后異步追加任務代碼到主隊列令野,并開始執(zhí)行
        NSLog(@"after---%@",[NSThread currentThread]);  // 打印當前線程
    });
}

3. 一次性代碼(只執(zhí)行一次):dispatch_once

即使在多線程的環(huán)境下,dispatch_once 也可以保證線程安全徽级。

- (void)once {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // 只執(zhí)行 1 次的代碼(這里面默認是線程安全的)
    });
}

4.快速迭代方法:dispatch_apply

按照指定的次數(shù)將指定的任務追加到指定的隊列中气破,并等待全部隊列執(zhí)行結束。
如果是在串行隊列中使用 dispatch_apply餐抢,那么就和 for 循環(huán)一樣现使,按順序同步執(zhí)行低匙。但是這樣就體現(xiàn)不出快速迭代的意義了。

我們可以利用并發(fā)隊列進行異步執(zhí)行碳锈。比如說遍歷 0~5 這 6 個數(shù)字顽冶,for 循環(huán)的做法是每次取出一個元素,逐個遍歷售碳。dispatch_apply 可以 在多個線程中同時(異步)遍歷多個數(shù)字强重。

還有一點,無論是在串行隊列贸人,還是并發(fā)隊列中间景,dispatch_apply 都會等待全部任務執(zhí)行完畢,這點就像是同步操作艺智,也像是隊列組中的 dispatch_group_wait方法倘要。

- (void)apply {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    NSLog(@"apply---begin");
    dispatch_apply(6, queue, ^(size_t index) {
        NSLog(@"%zd---%@",index, [NSThread currentThread]);
    });
    NSLog(@"apply---end");
}

5.隊列組:dispatch_group

dispatch_group_notify

- (void)groupNotify {
    dispatch_group_t group =  dispatch_group_create();
  
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 追加任務 1
        [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 追加任務 2
        [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // 等前面的異步任務 1、任務 2 都執(zhí)行完畢后十拣,回到主線程執(zhí)行下邊任務
        [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
    });
}

dispatch_group_wait(阻塞當前線程)

/**
 * 隊列組 dispatch_group_wait
 */
- (void)groupWait {
    dispatch_group_t group =  dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 追加任務 1
        [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 追加任務 2
        [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
    });
    // 等待上面的任務全部完成后封拧,會往下繼續(xù)執(zhí)行(會阻塞當前線程)
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    
    NSLog(@"group---end");
}

dispatch_group_enter、dispatch_group_leave

/**
 * 隊列組 dispatch_group_enter夭问、dispatch_group_leave
 */
- (void)groupEnterAndLeave {
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印當前線程
    NSLog(@"group---begin");
    
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        // 追加任務 1
        [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
        NSLog(@"1---%@",[NSThread currentThread]);      // 打印當前線程

        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        // 追加任務 2
        [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
        NSLog(@"2---%@",[NSThread currentThread]);      // 打印當前線程
        
        dispatch_group_leave(group);
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // 等前面的異步操作都執(zhí)行完畢后泽西,回到主線程.
        [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
        NSLog(@"3---%@",[NSThread currentThread]);      // 打印當前線程
    
        NSLog(@"group---end");
    });
}

6 dispatch_semaphore(信號量)

dispatch_semaphore_create:創(chuàng)建一個 Semaphore 并初始化信號的總量
dispatch_semaphore_signal:發(fā)送一個信號,讓信號總量加 1
dispatch_semaphore_wait:可以使總信號量減 1缰趋,信號總量小于 0 時就會一直等待(阻塞所在線程)尝苇,否則就可以正常執(zhí)行。




?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末埠胖,一起剝皮案震驚了整個濱河市糠溜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌直撤,老刑警劉巖非竿,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異谋竖,居然都是意外死亡红柱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門蓖乘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锤悄,“玉大人,你說我怎么就攤上這事嘉抒×憔郏” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長隶症。 經(jīng)常有香客問我政模,道長,這世上最難降的妖魔是什么蚂会? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任淋样,我火速辦了婚禮,結果婚禮上胁住,老公的妹妹穿的比我還像新娘趁猴。我一直安慰自己,他們只是感情好彪见,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布儡司。 她就那樣靜靜地躺著,像睡著了一般企巢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上让蕾,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天浪规,我揣著相機與錄音,去河邊找鬼探孝。 笑死笋婿,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的顿颅。 我是一名探鬼主播缸濒,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼粱腻!你這毒婦竟也來了庇配?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤绍些,失蹤者是張志新(化名)和其女友劉穎捞慌,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體柬批,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡啸澡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了氮帐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嗅虏。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖上沐,靈堂內(nèi)的尸體忽然破棺而出皮服,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站北发,受9級特大地震影響刚操,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜舟铜,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望奠衔。 院中可真熱鬧谆刨,春花似錦、人聲如沸归斤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽脏里。三九已至她我,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間迫横,已是汗流浹背番舆。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留矾踱,地道東北人恨狈。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像呛讲,于是被迫代替她去往敵國和親禾怠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

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