1. GCD相關(guān)概念
任務(wù):就是執(zhí)行操作的意思玄呛,就是你在線程中執(zhí)行的那段代碼蛉顽。在 GCD 中是放在 block 中的尤筐。執(zhí)行任務(wù)有兩種方式:『同步執(zhí)行』 和 『異步執(zhí)行』诉探。兩者的主要區(qū)別是:是否等待隊(duì)列的任務(wù)執(zhí)行結(jié)束日熬,以及是否具備開啟新線程的能力。
同步執(zhí)行(sync):同步添加任務(wù)到指定的隊(duì)列中肾胯,在添加的任務(wù)執(zhí)行結(jié)束之前竖席,會(huì)一直等待,直到隊(duì)列里面的任務(wù)完成之后再繼續(xù)執(zhí)行敬肚。只能在當(dāng)前線程中執(zhí)行任務(wù)毕荐,不具備開啟新線程的能力。
異步執(zhí)行(async):異步添加任務(wù)到指定的隊(duì)列中艳馒,它不會(huì)做任何等待憎亚,可以繼續(xù)執(zhí)行任務(wù)员寇。可以在新的線程中執(zhí)行任務(wù)第美,具備開啟新線程的能力蝶锋。
隊(duì)列(Dispatch Queue):這里的隊(duì)列指執(zhí)行任務(wù)的等待隊(duì)列,即用來存放任務(wù)的隊(duì)列什往。隊(duì)列是一種特殊的線性表扳缕,采用 FIFO(先進(jìn)先出)的原則,即新任務(wù)總是被插入到隊(duì)列的末尾别威,而讀取任務(wù)的時(shí)候總是從隊(duì)列的頭部開始讀取躯舔。每讀取一個(gè)任務(wù),則從隊(duì)列中釋放一個(gè)任務(wù)兔港。
串行隊(duì)列(Serial Dispatch Queue):每次只有一個(gè)任務(wù)被執(zhí)行庸毫。讓任務(wù)一個(gè)接著一個(gè)地執(zhí)行。(只開啟一個(gè)線程衫樊,一個(gè)任務(wù)執(zhí)行完畢后飒赃,再執(zhí)行下一個(gè)任務(wù))
并發(fā)隊(duì)列(Concurrent Dispatch Queue):可以讓多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行。(可以開啟多個(gè)線程科侈,并且同時(shí)執(zhí)行任務(wù))。并發(fā)隊(duì)列 的并發(fā)功能只有在異步(dispatch_async)方法下才有效臀栈。
2. GCD 的使用步驟
1.創(chuàng)建一個(gè)隊(duì)列(串行隊(duì)列或并發(fā)隊(duì)列)蔫慧;
2.將任務(wù)追加到任務(wù)的等待隊(duì)列中,然后系統(tǒng)就會(huì)根據(jù)任務(wù)類型執(zhí)行任務(wù)(同步執(zhí)行或異步執(zhí)行)权薯。
3. 隊(duì)列的創(chuàng)建方法 / 獲取方法
使用 dispatch_queue_create 方法來創(chuàng)建隊(duì)列姑躲。該方法需要傳入兩個(gè)參數(shù),第一個(gè)參數(shù)表示隊(duì)列的唯一標(biāo)識(shí)符,用于 DEBUG盟蚣,可為空黍析。第二個(gè)參數(shù)用來識(shí)別是串行隊(duì)列還是并發(fā)隊(duì)列。DISPATCH_QUEUE_SERIAL 表示串行隊(duì)列屎开,DISPATCH_QUEUE_CONCURRENT 表示并發(fā)隊(duì)列阐枣。
// 串行隊(duì)列的創(chuàng)建方法
dispatch_queue_t queue = dispatch_queue_create("nameValue", DISPATCH_QUEUE_SERIAL);
// 并發(fā)隊(duì)列的創(chuàng)建方法
dispatch_queue_t queue = dispatch_queue_create("nameValue", DISPATCH_QUEUE_CONCURRENT);
對于串行隊(duì)列,GCD 提供了的一種特殊的串行隊(duì)列:『主隊(duì)列(Main Dispatch Queue)』奄抽。所有放在主隊(duì)列中的任務(wù)蔼两,都會(huì)放到主線程中執(zhí)行〕讯龋可使用 dispatch_get_main_queue() 方法獲得主隊(duì)列额划。
// 主隊(duì)列的獲取方法
dispatch_queue_t queue = dispatch_get_main_queue();
對于并發(fā)隊(duì)列,GCD 默認(rèn)提供了 『全局并發(fā)隊(duì)列(Global Dispatch Queue)』档泽。
可以使用 dispatch_get_global_queue 方法來獲取全局并發(fā)隊(duì)列锁孟。需要傳入兩個(gè)參數(shù)彬祖。第一個(gè)參數(shù)表示隊(duì)列優(yōu)先級,一般用 DISPATCH_QUEUE_PRIORITY_DEFAULT品抽。第二個(gè)參數(shù)暫時(shí)沒用,用 0 即可甜熔。
// 全局并發(fā)隊(duì)列的獲取方法
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
4. 任務(wù)的創(chuàng)建方法
// 同步執(zhí)行任務(wù)創(chuàng)建方法
dispatch_sync(queue, ^{
});
// 異步執(zhí)行任務(wù)創(chuàng)建方法
dispatch_async(queue, ^{
});
5.1 隊(duì)列和任務(wù)的組合使用
區(qū)別 | 并發(fā)隊(duì)列 | 串行隊(duì)列 | 主隊(duì)列 |
---|---|---|---|
同步(sync) | 沒有開啟新線程圆恤,串行執(zhí)行任務(wù) | 沒有開啟新線程,串行執(zhí)行任務(wù) | 死鎖腔稀,卡住不執(zhí)行 |
異步(async) | 有開啟新線程盆昙,并發(fā)執(zhí)行任務(wù) | 有開啟新線程(1條),串行執(zhí)行任務(wù) | 沒有開啟新線程焊虏,串行執(zhí)行任務(wù) |
從上邊可看出:『主線程』 中調(diào)用 『主隊(duì)列』+『同步執(zhí)行』 會(huì)導(dǎo)致死鎖問題淡喜。
這是因?yàn)?主隊(duì)列中追加的同步任務(wù) 和 主線程本身的任務(wù) 兩者之間相互等待,阻塞了 『主隊(duì)列』诵闭,最終造成了主隊(duì)列所在的線程(主線程)死鎖問題炼团。
而如果我們在 『其他線程』 調(diào)用 『主隊(duì)列』+『同步執(zhí)行』,則不會(huì)阻塞 『主隊(duì)列』疏尿,自然也不會(huì)造成死鎖問題瘟芝。最終的結(jié)果是:不會(huì)開啟新線程,串行執(zhí)行任務(wù)褥琐。
5.2 隊(duì)列嵌套情況下锌俱,不同組合方式區(qū)別
區(qū)別 | 『異步執(zhí)行+并發(fā)隊(duì)列』嵌套『同一個(gè)并發(fā)隊(duì)列』 | 『同步執(zhí)行+并發(fā)隊(duì)列』嵌套『同一個(gè)并發(fā)隊(duì)列』 | 『異步執(zhí)行+串行隊(duì)列』嵌套『同一個(gè)串行隊(duì)列』 | 『同步執(zhí)行+串行隊(duì)列』嵌套『同一個(gè)串行隊(duì)列』 |
---|---|---|---|---|
同步(sync) | 沒有開啟新的線程,串行執(zhí)行任務(wù) | 沒有開啟新線程敌呈,串行執(zhí)行任務(wù) | 死鎖卡住不執(zhí)行 | 死鎖卡住不執(zhí)行 |
異步(async) | 有開啟新線程贸宏,并發(fā)執(zhí)行任務(wù) | 有開啟新線程,并發(fā)執(zhí)行任務(wù) | 有開啟新線程(1 條)磕洪,串行執(zhí)行任務(wù) | 有開啟新線程(1 條)吭练,串行執(zhí)行任務(wù) |
6. 具體代碼組合使用詳情 ( 線程number=1 就是主線程 大于1就是子線程 )
- 同步(sync) + 并發(fā)隊(duì)列 ( 沒有開啟子線程,串行執(zhí)行任務(wù),在主線程 )
// 同步(sync) + 并發(fā)隊(duì)列 (沒有開啟子線程,串行執(zhí)行任務(wù),在主線程)
-(void)startGCDAction{
// 1.1 創(chuàng)建并發(fā)隊(duì)列
// dispatch_queue_t queueObj = dispatch_queue_create("nameValue",DISPATCH_QUEUE_CONCURRENT);
// 1.2 獲取全局并發(fā)隊(duì)列
dispatch_queue_t queueObj = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 2.0 同步
dispatch_sync(queueObj, ^{
NSLog(@"做任務(wù)(1),當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_sync(queueObj, ^{
NSLog(@"做任務(wù)(2),當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_sync(queueObj, ^{
NSLog(@"做任務(wù)(3),當(dāng)前線程:%@",[NSThread currentThread]);
});
}
最終運(yùn)行結(jié)果:
TestModel[85321:13209706] 做任務(wù)(1),當(dāng)前線程:<NSThread: 0x281beda40>{number = 1, name = main}
TestModel[85321:13209706] 做任務(wù)(2),當(dāng)前線程:<NSThread: 0x281beda40>{number = 1, name = main}
TestModel[85321:13209706] 做任務(wù)(3),當(dāng)前線程:<NSThread: 0x281beda40>{number = 1, name = main}
- 異步(async) + 并發(fā)隊(duì)列 ( 有開啟子線程,并發(fā)執(zhí)行任務(wù),在子線程 )
// 異步(async) + 并發(fā)隊(duì)列(有開啟子線程,并發(fā)執(zhí)行任務(wù),在子線程)
-(void)startGCDAction{
// 1.1 創(chuàng)建并發(fā)隊(duì)列
dispatch_queue_t queueObj = dispatch_queue_create("nameValue",DISPATCH_QUEUE_CONCURRENT);
// 1.2 獲取全局并發(fā)隊(duì)列
// dispatch_queue_t queueObj = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 2.0 異步
dispatch_async(queueObj, ^{
NSLog(@"做任務(wù)(1),當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_async(queueObj, ^{
NSLog(@"做任務(wù)(2),當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_async(queueObj, ^{
NSLog(@"做任務(wù)(3),當(dāng)前線程:%@",[NSThread currentThread]);
});
}
最終運(yùn)行結(jié)果:
TestModel[85332:13211973] 做任務(wù)(2),當(dāng)前線程:<NSThread: 0x281405a80>{number = 4, name = (null)}
TestModel[85332:13211979] 做任務(wù)(1),當(dāng)前線程:<NSThread: 0x281408cc0>{number = 3, name = (null)}
TestModel[85332:13211973] 做任務(wù)(3),當(dāng)前線程:<NSThread: 0x281405a80>{number = 4, name = (null)}
- 同步(sync) + 串行隊(duì)列 ( 沒有開啟子線程,串行執(zhí)行任務(wù),在主線程 )
// 同步(sync) + 串行隊(duì)列 (沒有開啟子線程,串行執(zhí)行任務(wù),在主線程)
-(void)startGCDAction{
// 1.0 創(chuàng)建串行隊(duì)列
dispatch_queue_t queueObj = dispatch_queue_create("nameValue", DISPATCH_QUEUE_SERIAL);
// 2.0 同步
dispatch_sync(queueObj, ^{
NSLog(@"做任務(wù)(1),當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_sync(queueObj, ^{
NSLog(@"做任務(wù)(2),當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_sync(queueObj, ^{
NSLog(@"做任務(wù)(3),當(dāng)前線程:%@",[NSThread currentThread]);
});
}
最終運(yùn)行結(jié)果:
TestModel[85392:13219612] 做任務(wù)(1),當(dāng)前線程:<NSThread: 0x2822a5a40>{number = 1, name = main}
TestModel[85392:13219612] 做任務(wù)(2),當(dāng)前線程:<NSThread: 0x2822a5a40>{number = 1, name = main}
TestModel[85392:13219612] 做任務(wù)(3),當(dāng)前線程:<NSThread: 0x2822a5a40>{number = 1, name = main}
- 異步(async) + 串行隊(duì)列 ( 只開啟一條子線程,串行執(zhí)行任務(wù) )
// 異步(async) + 串行隊(duì)列 (只開啟一條子線程,串行執(zhí)行任務(wù))
-(void)startGCDAction{
// 1.0 創(chuàng)建串行隊(duì)列
dispatch_queue_t queueObj = dispatch_queue_create("nameValue", DISPATCH_QUEUE_SERIAL);
// 2.0 異步
dispatch_async(queueObj, ^{
NSLog(@"做任務(wù)(1),當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_async(queueObj, ^{
NSLog(@"做任務(wù)(2),當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_async(queueObj, ^{
NSLog(@"做任務(wù)(3),當(dāng)前線程:%@",[NSThread currentThread]);
});
}
最終運(yùn)行結(jié)果:
TestModel[85396:13221073] 做任務(wù)(1),當(dāng)前線程:<NSThread: 0x28106c940>{number = 3, name = (null)}
TestModel[85396:13221073] 做任務(wù)(2),當(dāng)前線程:<NSThread: 0x28106c940>{number = 3, name = (null)}
TestModel[85396:13221073] 做任務(wù)(3),當(dāng)前線程:<NSThread: 0x28106c940>{number = 3, name = (null)}
- 同步(sync) + 主線程 ( 造成死鎖,主線程和同步任務(wù)相互等待 )
// 同步(sync) + 主線程 (造成死鎖,主線程和同步任務(wù)相互等待)
-(void)startGCDActionWithMainThread{
// 1.0 獲取主線程
dispatch_queue_main_t mainQueue = dispatch_get_main_queue();
// 2.0 同步
dispatch_sync(mainQueue, ^{
NSLog(@"做任務(wù)(1),當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_sync(mainQueue, ^{
NSLog(@"做任務(wù)(2),當(dāng)前線程:%@",[NSThread currentThread]);
});
NSLog(@"做任務(wù)(3),當(dāng)前線程:%@",[NSThread currentThread]);
}
最終運(yùn)行結(jié)果:
Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1004cb84c)
在 dispatch_sync(mainQueue, ^{ }); 報(bào)上訴錯(cuò)誤 三個(gè)都不會(huì)打印 因?yàn)槌绦蛑苯颖紳?
- 異步(async) + 主線程 ( 沒有開啟子線程,串行執(zhí)行任務(wù),在主線程 )
// 異步(async) + 主線程 (沒有開啟子線程,串行執(zhí)行任務(wù),在主線程)
-(void)startGCDActionWithMainThread{
// 1.0 獲取主線程
dispatch_queue_main_t mainQueue = dispatch_get_main_queue();
// 2.0 異步
dispatch_async(mainQueue, ^{
NSLog(@"做任務(wù)(1),當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_async(mainQueue, ^{
NSLog(@"做任務(wù)(2),當(dāng)前線程:%@",[NSThread currentThread]);
});
}
最終運(yùn)行結(jié)果:
TestModel[85332:13211973] 做任務(wù)(1),當(dāng)前線程:<NSThread: 0x280406e40>{number = 1, name = main}
TestModel[85332:13211973] 做任務(wù)(2),當(dāng)前線程:<NSThread: 0x280406e40>{number = 1, name = main}
7. GCD 線程之間的通信
在其子線程中完成了耗時(shí)操作后,需要回到主線程 (進(jìn)行 UI 刷新) 褐鸥,那么就用到了線程之間的通訊线脚。通過使用
1.1 獲取主線程 dispatch_queue_t mainQueue = dispatch_get_main_queue();
1.2 異步回到主線程 dispatch_async(mainQueue, ^{ } );
// 線程之間的通訊(子線程回到主線程)
-(void)startGCDCommunicationAction{
// 1.1 創(chuàng)建并發(fā)隊(duì)列
// dispatch_queue_t queueObj=dispatch_queue_create("nameValue",DISPATCH_QUEUE_CONCURRENT);
// 1.2 獲取全局并發(fā)隊(duì)列
dispatch_queue_t queueObj=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 2.0 異步
dispatch_async(queueObj, ^{
NSLog(@"做任務(wù)(1),當(dāng)前線程:%@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:3.0]; // 睡眠線程3秒,相當(dāng)于耗時(shí)操作
// 3.0 獲取主線程
dispatch_queue_t mainQueue=dispatch_get_main_queue();
// 4.0 異步回到主線程
dispatch_async(mainQueue, ^{
NSLog(@"回到主線程刷新UI操作,當(dāng)前線程:%@",[NSThread currentThread]);
});
});
}
最終運(yùn)行結(jié)果:
2019-08-11 12:26:51.973353 TestModel[85877:13291589] 做任務(wù)(1),當(dāng)前線程:<NSThread: 0x282f797c0>{number = 4, name = (null)}
2019-08-11 12:26:54.979122 TestModel[85877:13291523] 回到主線程刷新UI操作,當(dāng)前線程:<NSThread: 0x282f1ae40>{number = 1, name = main}
8. GCD 的其他方法
1. 柵欄函數(shù)(方法):dispatch_barrier_sync (同步 ) 和 dispatch_barrier_async (異步 ) 執(zhí)行完柵欄前面的操作之后,才執(zhí)行柵欄操作(子線程或主線程)叫榕,最后再執(zhí)行柵欄后邊的操作浑侥。
// 使用柵欄函數(shù),必須通過創(chuàng)建并發(fā)隊(duì)列 不能使用全局并發(fā)隊(duì)列
-(void)startGCDWithBarrier{
// 1.0 創(chuàng)建并發(fā)隊(duì)列 (這里不能用下面的 直接獲取全局并發(fā)隊(duì)列 只能通過創(chuàng)建才能體現(xiàn)出柵欄函數(shù))
dispatch_queue_t queueObj=dispatch_queue_create("nameValue", DISPATCH_QUEUE_CONCURRENT);
// 1.0 獲取全局并發(fā)隊(duì)列
// dispatch_queue_t queueObj=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 2.0 異步操作1
dispatch_async(queueObj, ^{
NSLog(@"做任務(wù)(1),當(dāng)前線程:%@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0]; // 睡眠線程1秒
});
// 2.0 異步操作2
dispatch_async(queueObj, ^{
NSLog(@"做任務(wù)(2),當(dāng)前線程:%@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:2.0]; // 睡眠線程2秒
});
// 3.0 同步柵欄函數(shù)(在主線程執(zhí)行操作,換成 async 就在子線程中)
dispatch_barrier_sync(queueObj, ^{
NSLog(@"柵欄函數(shù)做任務(wù)(????),當(dāng)前線程:%@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0]; // 睡眠線程2秒
});
// 2.0異步操作3
dispatch_async(queueObj, ^{
NSLog(@"做任務(wù)(3),當(dāng)前線程:%@",[NSThread currentThread]);
});
// 2.0異步操作4
dispatch_async(queueObj, ^{
NSLog(@"做任務(wù)(4),當(dāng)前線程:%@",[NSThread currentThread]);
});
}
最終運(yùn)行結(jié)果:
2019-08-11 12:49:37.631269 TestModel[85906:13296017] 做任務(wù)(1),當(dāng)前線程:<NSThread: 0x2806b1a00>{number = 4, name = (null)}
2019-08-11 12:49:38.632798 TestModel[85906:13296017] 做任務(wù)(2),當(dāng)前線程:<NSThread: 0x2806b1a00>{number = 4, name = (null)}
2019-08-11 12:49:40.634186 TestModel[85906:13295953] 柵欄函數(shù)做任務(wù)(????),當(dāng)前線程:<NSThread: 0x2806d3040>{number = 1, name = main}
2019-08-11 12:49:41.635503 TestModel[85906:13296017] 做任務(wù)(3),當(dāng)前線程:<NSThread: 0x2806b1a00>{number = 4, name = (null)}
2019-08-11 12:49:41.635610 TestModel[85906:13296017] 做任務(wù)(4),當(dāng)前線程:<NSThread: 0x2806b1a00>{number = 4, name = (null)}
2. 延時(shí)執(zhí)行函數(shù)(方法):dispatch_after 其并不是在指定時(shí)間之后才開始執(zhí)行處理,而是在指定時(shí)間之后將任務(wù)追加到主隊(duì)列中(一定在主線程)晰绎。
// GCD延時(shí)函數(shù)
-(void)startGCDWithAfterFun{
NSLog(@"來咯寓落!來咯!她們都來了 ?? ");
// 獲取全局的并發(fā)隊(duì)列
dispatch_queue_t queueObj=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queueObj, ^{
NSLog(@"調(diào)用前的線程是:%@ ",[NSThread currentThread]);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"3秒后才調(diào)用我這個(gè)操作,當(dāng)前線程是:%@ ",[NSThread currentThread]);
});
});
}
最終運(yùn)行結(jié)果:
2019-08-11 13:09:48.371427 TestModel[85920:13298751] 來咯荞下!來咯伶选!她們都來了 ??
2019-08-11 13:09:48.371942 TestModel[85920:13298827] 調(diào)用前的線程是:<NSThread: 0x280b38f80>{number = 4, name = (null)}
2019-08-11 13:09:51.613677 TestModel[85920:13298751] 3秒后才調(diào)用我這個(gè)操作,當(dāng)前線程是:<NSThread: 0x280b55880>{number = 1, name = main}
3. 一次性函數(shù)(方法):dispatch_once 該函數(shù)中的代碼整個(gè)程序運(yùn)行過程中只會(huì)執(zhí)行一次史飞。
// GCD一次性函數(shù)(只會(huì)執(zhí)行一次)
-(void)startGCDWithOnceFun{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"你只能打我一次哦(??????),不服來戰(zhàn)!");
});
}
我在 -(void)viewDidLoad {} 中調(diào)用多次,最終結(jié)果只會(huì)輸出一次
-(void)viewDidLoad {
[super viewDidLoad];
[self startGCDWithOnceFun];
[self startGCDWithOnceFun];
[self startGCDWithOnceFun];
[self startGCDWithOnceFun];
}
最終運(yùn)行結(jié)果:
TestModel[85923:13300176] 你只能打我一次哦(??????),不服來戰(zhàn)仰税!
4. GCD 隊(duì)列組 dispatch_group_async 分別異步執(zhí)行2個(gè)耗時(shí)任務(wù)构资,然后當(dāng)2個(gè)耗時(shí)任務(wù)都執(zhí)行完畢后再回到主線程執(zhí)行任務(wù)。監(jiān)聽隊(duì)列組中任務(wù)完成 dispatch_group_notify
// GCD之隊(duì)列組
-(void)startGCDWithGroup{
// 1.0 創(chuàng)建一個(gè)隊(duì)列組
dispatch_group_t groupObj=dispatch_group_create();
// 2.1 創(chuàng)建并發(fā)隊(duì)列
dispatch_queue_t queueObj=dispatch_queue_create("nameValue", DISPATCH_QUEUE_CONCURRENT);
// 2.2 獲取全局的并發(fā)隊(duì)列
// dispatch_queue_t queueObj=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 3.1 使用隊(duì)列組執(zhí)行任務(wù)(1)
dispatch_group_async(groupObj, queueObj, ^{
NSLog(@"列組中,子線程執(zhí)行任務(wù)(1),當(dāng)前線程是:%@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:2.0];
});
// 3.1 使用隊(duì)列組執(zhí)行任務(wù)(1)
dispatch_group_async(groupObj, queueObj, ^{
NSLog(@"列組中,子線程隊(duì)執(zhí)行任務(wù)(2),當(dāng)前線程是:%@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:3.0];
});
// 4.0 隊(duì)列組中任務(wù)執(zhí)行完畢 回到主線程
dispatch_group_notify(groupObj, dispatch_get_main_queue(), ^{
NSLog(@"隊(duì)列組中任務(wù)執(zhí)行完畢調(diào)用,回到主線程,當(dāng)前線程是:%@",[NSThread currentThread]);
});
}
最終運(yùn)行結(jié)果:
2019-08-11 17:07:44.674 TestModel[86321:13347506] 列組中,子線程隊(duì)執(zhí)行任務(wù)(2),當(dāng)前線程是:<NSThread: 0x281365880>{number = 3, name = (null)}
2019-08-11 17:07:44.675 TestModel[86321:13347505] 列組中,子線程執(zhí)行任務(wù)(1),當(dāng)前線程是:<NSThread: 0x281330940>{number = 4, name = (null)}
2019-08-11 17:07:47.680 TestModel[86321:13347495] 隊(duì)列組中任務(wù)執(zhí)行完畢調(diào)用,回到主線程,當(dāng)前線程是:<NSThread: 0x281351340>{number = 1, name = main}
5. dispatch_group_wait : 暫停當(dāng)前線程(阻塞當(dāng)前線程) dispatch_semaphore :(線程加鎖)