iOS 多線程 GCD

線程vs進(jìn)程

進(jìn)程: 對(duì)于移動(dòng)端來講一個(gè)APP的啟動(dòng)就相當(dāng)于手機(jī)系統(tǒng)開啟了一個(gè)進(jìn)程,每個(gè)程序只能開啟一個(gè)進(jìn)程递礼,也就是說對(duì)于手機(jī)系統(tǒng)而言都是單進(jìn)程應(yīng)用。

線程: 可以理解為獨(dú)立執(zhí)行的代碼段喂饥,一個(gè)線程同時(shí)間只能執(zhí)行一個(gè)任務(wù)亲轨。

提示: iOS程序啟動(dòng)之后就創(chuàng)建了一個(gè)主線程,用于刷新程序UI孩锡,所以才有你看到的絢麗多彩的界面酷宵。

同步和異步

線程分同步sync和異步async之分

  • 同步線程:同步線程會(huì)阻塞當(dāng)前線程去執(zhí)行線程內(nèi)的任務(wù),執(zhí)行完之后才會(huì)反回當(dāng)前線程躬窜。
  • 異步線程:異步線程不會(huì)阻塞當(dāng)前線程浇垦,會(huì)開啟其他線程去執(zhí)行線程內(nèi)的任務(wù)。(推薦使用)
dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@"異步執(zhí)行任務(wù),不會(huì)阻塞當(dāng)前線程");
});
dispatch_sync(dispatch_get_main_queue(), ^{
  NSLog(@"同步執(zhí)行任務(wù),注意——>");//這段代碼不會(huì)打印荣挨,會(huì)產(chǎn)生死鎖男韧,因?yàn)橥街骶€程會(huì)造成主隊(duì)列線程相互等待朴摊。
});

隊(duì)列

GCD中一個(gè)block代碼塊就是一個(gè)隊(duì)列,隊(duì)列可以是并行也可以是串行的煌抒。默認(rèn)情況下仍劈,它們是串行的,也就是說寡壮,任何給定的時(shí)間內(nèi)贩疙,只能有一個(gè)單獨(dú)的 block 運(yùn)行。隊(duì)列也可以是并行的况既,也就是同一時(shí)間內(nèi)允許多個(gè) block 一起執(zhí)行这溅。其實(shí)隊(duì)列很大程度的幫助我們更方便的使用多線程來調(diào)度我們的功能。

主線程隊(duì)列

1.獲取主線程串行隊(duì)列

dispatch_queue_t mainQueue = dispatch_get_main_queue();//注意:禁止再次隊(duì)列中同步執(zhí)行任務(wù)棒仍。因?yàn)闀?huì)產(chǎn)生死鎖

2.主線程串行隊(duì)列異步執(zhí)行任務(wù)悲靴,在主線程運(yùn)行,不會(huì)產(chǎn)生死鎖

dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^{
    NSLog(@"主隊(duì)列");
});

全局并發(fā)隊(duì)列

耗時(shí)的操作莫其,比如讀取網(wǎng)絡(luò)數(shù)據(jù)癞尚,IO,數(shù)據(jù)庫(kù)讀寫等,我們會(huì)在另外一個(gè)線程中處理這些操作乱陡,然后通知主線程更新界面
1.獲取全局并發(fā)隊(duì)列

//全局并發(fā)隊(duì)列中 GCD 為我們提供了優(yōu)先級(jí)
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/*
 #define DISPATCH_QUEUE_PRIORITY_HIGH 2
 #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
 #define DISPATCH_QUEUE_PRIORITY_LOW (-2)
 #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
 */

2.多個(gè)線程任務(wù)在全局并發(fā)隊(duì)列中執(zhí)行

dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"current task");
dispatch_async(globalQueue, ^{
    NSLog(@"最先加入全局并發(fā)隊(duì)列");
});
dispatch_async(globalQueue, ^{
    NSLog(@"次加入全局并發(fā)隊(duì)列");
});
NSLog(@"next task");

控制臺(tái)輸出:

2015-11-18 16:54:52.202 Whisper[39827:403208] current task
2015-11-18 16:54:52.203 Whisper[39827:403208] next task
2015-11-18 16:54:52.205 Whisper[39827:403309] 最先加入全局并發(fā)隊(duì)列
2015-11-18 16:54:52.205 Whisper[39827:403291] 次加入全局并發(fā)隊(duì)列

異步線程的執(zhí)行順序是不確定的浇揩。幾乎同步開始執(zhí)行
全局并發(fā)隊(duì)列由系統(tǒng)默認(rèn)生成的,所以無(wú)法調(diào)用dispatch_resume()和dispatch_suspend()來控制執(zhí)行繼續(xù)或中斷憨颠。

自定義隊(duì)列

自定義隊(duì)列就是拋開系統(tǒng)為我們創(chuàng)建的全局主隊(duì)列以及全局并發(fā)隊(duì)列胳徽,自己創(chuàng)建一個(gè)隊(duì)列

//自定義串行隊(duì)列
dispatch_queue_t serialQueue = dispatch_queue_create("com.custom.serialQueue", DISPATCH_QUEUE_SERIAL);
//自定義并行隊(duì)列
dispatch_queue_t conCurrentQueue = dispatch_queue_create("com.custom.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);

dispatch_queue_create 后面第一個(gè)參數(shù)通常用反域名字符表示,你可以作為你識(shí)別的唯一名稱爽彤,方便調(diào)試
有了隊(duì)列我們就可以添加任務(wù)來執(zhí)行了

示例:

dispatch_queue_t conCurrentQueue = dispatch_queue_create("com.dullgrass.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"current task");
dispatch_async(conCurrentQueue, ^{
   NSLog(@"先加入隊(duì)列");
});
dispatch_async(conCurrentQueue, ^{
   NSLog(@"次加入隊(duì)列");
});
NSLog(@"next task");

控制臺(tái)輸出如下:

2015-11-19 10:45:22.290 Whisper[1050:26445] current task
2015-11-19 10:45:22.290 Whisper[1050:26445] next task
2015-11-19 10:45:22.290 Whisper[1050:26505] 次加入隊(duì)列
2015-11-19 10:45:22.290 Whisper[1050:26500] 先加入隊(duì)列

隊(duì)列組

當(dāng)遇到需要執(zhí)行多個(gè)線程并發(fā)執(zhí)行养盗,然后等多個(gè)線程都結(jié)束之后,再匯總執(zhí)行結(jié)果時(shí)可以用group queue

dispatch_group_t groupQueue = dispatch_group_create();

使用示例:

dispatch_queue_t conCurrentGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_group_t groupQueue = dispatch_group_create();
NSLog(@"current task");
dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{
   NSLog(@"并行任務(wù)1");
});
dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{
   NSLog(@"并行任務(wù)2");
});
dispatch_group_notify(groupQueue, mainQueue, ^{
   NSLog(@"groupQueue中的任務(wù) 都執(zhí)行完成,回到主線程更新UI");
});
NSLog(@"next task");

控制臺(tái)輸出:

2017-08-15 17:42:42.355 TestProject[21907:682737] current task
2017-08-15 17:42:42.356 TestProject[21907:682737] next task
2017-08-15 17:42:42.356 TestProject[21907:682850] 并行任務(wù)1
2017-08-15 17:42:42.356 TestProject[21907:682849] 并行任務(wù)2
2017-08-15 17:42:42.504 TestProject[21907:682737] groupQueue中的任務(wù) 都執(zhí)行完成,回到主線程更新UI
//可以阻塞當(dāng)前線程 起到延遲等待效果
dispatch_group_wait(groupQueue, delayTime);

GCD 系統(tǒng)常用的 dispatch 方法

1.dispatch_once 實(shí)現(xiàn)單利模式

+ (UIColor *)defaultInstance;
{
    static UIColor *color;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        color = [UIColor colorWithRed:0.380f green:0.376f blue:0.376f alpha:1.000f];
    });
    return color;
}

上面的 block 只會(huì)運(yùn)行一次适篙。并且在連續(xù)的調(diào)用中往核,這種檢查是很高效的

2.dispatch_after被用作延遲添加

dispatch_queue_t mainQueue = dispatch_get_main_queue();
NSLog(@"current task");
dispatch_after(delayTime3, mainQueue, ^{
  NSLog(@"3秒之后添加到隊(duì)列");
});
dispatch_after(delayTime2, mainQueue, ^{
   NSLog(@"2秒之后添加到隊(duì)列");
});
NSLog(@"next task");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    NSLog(@"延遲兩秒執(zhí)行");
});

3.dispatch_apply

dispatch_apply函數(shù)的功能:把一項(xiàng)任務(wù)提交到隊(duì)列中多次執(zhí)行,隊(duì)列可以是串行也可以是并行嚷节,dispatch_apply不會(huì)立刻返回铆铆,在執(zhí)行完block中的任務(wù)后才會(huì)返回,是同步執(zhí)行的函數(shù)丹喻。

dispatch_queue_t seriaQueue = dispatch_queue_create("com.seriaQueue", DISPATCH_QUEUE_SERIAL);
dispatch_apply(3, seriaQueue, ^(size_t index) {
    index++;
    NSLog(@"index=%zu",index);
});
NSLog(@"執(zhí)行完成");

控制臺(tái)輸出:

//如果 seriaQueue 為并行隊(duì)列 index 也可能是無(wú)須輸出
2017-08-15 17:56:09.125 TestProject[22222:694749] index=1
2017-08-15 17:56:09.125 TestProject[22222:694749] index=2
2017-08-15 17:56:09.126 TestProject[22222:694749] index=3
2017-08-15 17:56:09.126 TestProject[22222:694749] 執(zhí)行完成

4.dispatch_barrier_async 柵欄的作用

功能:是在并行隊(duì)列中,等待在dispatch_barrier_async之前加入的隊(duì)列全部執(zhí)行完成之后(這些任務(wù)是并發(fā)執(zhí)行的)再執(zhí)行dispatch_barrier_async中的任務(wù)翁都,dispatch_barrier_async中的任務(wù)執(zhí)行完成之后碍论,再去執(zhí)行在dispatch_barrier_async之后加入到隊(duì)列中的任務(wù)(這些任務(wù)是并發(fā)執(zhí)行的)。

示例:

dispatch_queue_t conCurrentQueue = dispatch_queue_create("com.dullgrass.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(conCurrentQueue, ^{
  NSLog(@"dispatch 1");
});
dispatch_async(conCurrentQueue, ^{
   NSLog(@"dispatch 2");
});
dispatch_barrier_async(conCurrentQueue, ^{
   NSLog(@"dispatch barrier");
});
dispatch_async(conCurrentQueue, ^{
   NSLog(@"dispatch 3");
});
dispatch_async(conCurrentQueue, ^{
   NSLog(@"dispatch 4");
});

控制臺(tái)輸出:

2015-11-19 18:12:34.125 Whisper[22633:297257] dispatch 1
2015-11-19 18:12:34.125 Whisper[22633:297258] dispatch 2
2015-11-19 18:12:34.126 Whisper[22633:297258] dispatch barrier
2015-11-19 18:12:34.127 Whisper[22633:297258] dispatch 3
2015-11-19 18:12:34.127 Whisper[22633:297257] dispatch 4
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末柄慰,一起剝皮案震驚了整個(gè)濱河市鳍悠,隨后出現(xiàn)的幾起案子税娜,更是在濱河造成了極大的恐慌,老刑警劉巖藏研,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件敬矩,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蠢挡,警方通過查閱死者的電腦和手機(jī)弧岳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來业踏,“玉大人禽炬,你說我怎么就攤上這事∏诩遥” “怎么了腹尖?”我有些...
    開封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)伐脖。 經(jīng)常有香客問我热幔,道長(zhǎng),這世上最難降的妖魔是什么讼庇? 我笑而不...
    開封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任绎巨,我火速辦了婚禮,結(jié)果婚禮上巫俺,老公的妹妹穿的比我還像新娘认烁。我一直安慰自己,他們只是感情好介汹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開白布却嗡。 她就那樣靜靜地躺著,像睡著了一般嘹承。 火紅的嫁衣襯著肌膚如雪窗价。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天叹卷,我揣著相機(jī)與錄音撼港,去河邊找鬼。 笑死骤竹,一個(gè)胖子當(dāng)著我的面吹牛帝牡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蒙揣,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼靶溜,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起罩息,我...
    開封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤嗤详,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后瓷炮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體葱色,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年娘香,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了苍狰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡茅主,死狀恐怖舞痰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情诀姚,我是刑警寧澤响牛,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站赫段,受9級(jí)特大地震影響呀打,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜糯笙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一贬丛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧给涕,春花似錦豺憔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至耘眨,卻和暖如春昼榛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背剔难。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工胆屿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人偶宫。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓非迹,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親纯趋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子彻秆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

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