一运悲、基本介紹
Grand Central Dispatch (GCD)是Apple開發(fā)的一個(gè)多核編程的較新的解決方法。它主要用于優(yōu)化應(yīng)用程序以支持多核處理器以及其他對(duì)稱多處理系統(tǒng)。它是一個(gè)在線程池模式的基礎(chǔ)上執(zhí)行的并行任務(wù)雏逾。
GCD是一個(gè)替代諸如NSThread等技術(shù)的很高效和強(qiáng)大的技術(shù)今豆。GCD完全可以處理諸如數(shù)據(jù)鎖定和資源泄漏等復(fù)雜的異步編程問題灯蝴。GCD的工作原理是讓一個(gè)程序,根據(jù)可用的處理資源聂渊,安排他們?cè)谌魏慰捎玫奶幚砥骱诵纳掀叫信抨?duì)執(zhí)行特定的任務(wù)差购。這個(gè)任務(wù)可以是一個(gè)功能或者一個(gè)程序段。
GCD中的一個(gè)任務(wù)可被用于創(chuàng)造一個(gè)被放置于隊(duì)列的工作項(xiàng)目或者事件源汉嗽。如果一個(gè)任務(wù)被分配到一個(gè)事件源欲逃,那么一個(gè)由功能或者程序塊組成的工作單元會(huì)被放置于一個(gè)適當(dāng)?shù)年?duì)列中。蘋果公司認(rèn)為GCD相比于普通的一個(gè)接一個(gè)的執(zhí)行任務(wù)的方式更為有效率饼暑。
使用GCD 有以下好處:
- GCD可用于多核的并行運(yùn)算稳析;
- GCD會(huì)自動(dòng)利用更多的 CPU 內(nèi)核(比如雙核、四核)弓叛;
- GCD會(huì)自動(dòng)管理線程的生命周期(創(chuàng)建線程彰居、調(diào)度任務(wù)、銷毀線程)撰筷;
- 只需要告訴GCD想要執(zhí)行什么任務(wù)陈惰,不需要編寫任何線程管理代碼,因?yàn)榫€程是安全的毕籽。
二抬闯、使用方式
GCD的使用需要任務(wù)和隊(duì)列的相互配合:
任務(wù):就是執(zhí)行GCD中放在 block 中的代碼塊。執(zhí)行任務(wù)有兩種方式:同步執(zhí)行(sync)和異步執(zhí)行(async)关筒。兩者的主要區(qū)別是:是否等待隊(duì)列的任務(wù)執(zhí)行結(jié)束溶握,以及是否具備開啟新線程的能力。
-
同步執(zhí)行(sync):同步添加任務(wù)到指定的隊(duì)列中蒸播,該任務(wù)會(huì)在等待指定隊(duì)列中其他任務(wù)執(zhí)行完成后再執(zhí)行睡榆。而添加的任務(wù)只能在當(dāng)前線程中執(zhí)行任務(wù),不具備開啟新線程的能力。
同步執(zhí)行創(chuàng)建方式:
//同步執(zhí)行
dispatch_sync(queue, ^{
//添加執(zhí)行任務(wù)
});
-
異步執(zhí)行(async):異步添加任務(wù)到指定的隊(duì)列中肉微,該任務(wù)不會(huì)等待隊(duì)列中其他任務(wù)執(zhí)行完成匾鸥,直接開始執(zhí)行。而添加的任務(wù)可以在新的線程中執(zhí)行任務(wù)碉纳,具備開啟新線程的能力(開啟一個(gè)還是多個(gè)線程需要根據(jù)執(zhí)行隊(duì)列來確定)勿负。
異步執(zhí)行創(chuàng)建方式:
//異步執(zhí)行
dispatch_async(queue, ^{
//添加執(zhí)行任務(wù)
});
其中的queue就是我們所需要?jiǎng)?chuàng)建的執(zhí)行隊(duì)列。
隊(duì)列(Dispatch Queue):這里的隊(duì)列指執(zhí)行任務(wù)的等待隊(duì)列劳曹,即用來存放任務(wù)的隊(duì)列奴愉。隊(duì)列是一種特殊的線性表,采用 FIFO(先進(jìn)先出)的原則铁孵,即新任務(wù)總是被插入到隊(duì)列的末尾锭硼,而讀取任務(wù)的時(shí)候總是從隊(duì)列的頭部開始讀取。每讀取一個(gè)任務(wù)蜕劝,則從隊(duì)列中釋放一個(gè)任務(wù)檀头。在 GCD 中有兩種隊(duì)列:串行隊(duì)列和并發(fā)隊(duì)列。兩者都符合 FIFO(先進(jìn)先出)的原則岖沛。兩者的主要區(qū)別是:執(zhí)行順序不同暑始,以及開啟線程數(shù)不同。
-
串行隊(duì)列(Serial Dispatch Queue):只開啟一個(gè)線程婴削,在線程中任務(wù)是按順序的一個(gè)接一個(gè)的執(zhí)行廊镜。
串行隊(duì)列創(chuàng)建方式:
//創(chuàng)建串行隊(duì)列
dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);
//創(chuàng)建主隊(duì)列
dispatch_queue_t queue = dispatch_get_main_queue();
其中主隊(duì)列是GCD提供的一種特殊的串行隊(duì)列。
-
并發(fā)隊(duì)列(Concurrent Dispatch Queue):根據(jù)任務(wù)執(zhí)行的方式(同步執(zhí)行或異步執(zhí)行)來確定開啟一個(gè)或者多個(gè)線程唉俗。同步執(zhí)行時(shí)是在開啟的一個(gè)線程中按順序同步執(zhí)行嗤朴。異步執(zhí)行時(shí)是在開啟的多個(gè)線程中并發(fā)(同時(shí))執(zhí)行任務(wù)。
并行隊(duì)列創(chuàng)建方式:
//創(chuàng)建并發(fā)隊(duì)列
dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);
//創(chuàng)建全局并發(fā)隊(duì)列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
其中全局并發(fā)隊(duì)列是GCD提供的一種特殊的并發(fā)隊(duì)列虫溜。
下面介紹一下GCD任務(wù)和隊(duì)列的組合使用方式:
1雹姊、同步執(zhí)行 + 并發(fā)隊(duì)列
- 同步執(zhí)行不具備開啟新線程的能力,因此所有任務(wù)都是在當(dāng)前線程(主線程)中執(zhí)行的吼渡。
- 雖然并發(fā)隊(duì)列可以開啟多個(gè)線程并且可以同時(shí)執(zhí)行多個(gè)任務(wù)容为,但是因?yàn)橥綀?zhí)行任務(wù)不具備開啟新線程的能力乓序,因此只有當(dāng)前線程這一個(gè)線程寺酪,也就不存在并發(fā)。而且當(dāng)前線程只有等待當(dāng)前隊(duì)列中正在執(zhí)行的任務(wù)執(zhí)行完畢之后替劈,才能繼續(xù)接著執(zhí)行下面的操作(同步任務(wù)需要等待隊(duì)列的任務(wù)執(zhí)行結(jié)束)寄雀。所以任務(wù)只能一個(gè)接一個(gè)按順序執(zhí)行,不能同時(shí)被執(zhí)行陨献。
//1.同步執(zhí)行 + 并發(fā)隊(duì)列
- (instancetype)initSyncAndConcurrentDispatch {
if (self = [super init]) {
NSLog(@"currentThread---%@",[NSThread currentThread]);//打印當(dāng)前線程
NSLog(@"SyncAndConcurrent---begin");
dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);//創(chuàng)建并發(fā)隊(duì)列
dispatch_sync(queue, ^{//同步執(zhí)行
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)操作
NSLog(@"1---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
dispatch_sync(queue, ^{//同步執(zhí)行
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)操作
NSLog(@"2---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
dispatch_sync(queue, ^{//同步執(zhí)行
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)操作
NSLog(@"3---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
NSLog(@"SyncAndConcurrent---end");
}
return self;
}
輸出結(jié)果:
2018-07-18 14:06:25.808498+0800 GCD[3487:140302] currentThread---<NSThread: 0x604000065440>{number = 1, name = main}
2018-07-18 14:06:25.808716+0800 GCD[3487:140302] SyncAndConcurrent---begin
2018-07-18 14:06:27.810127+0800 GCD[3487:140302] 1---<NSThread: 0x604000065440>{number = 1, name = main}
2018-07-18 14:06:29.811518+0800 GCD[3487:140302] 1---<NSThread: 0x604000065440>{number = 1, name = main}
2018-07-18 14:06:31.812374+0800 GCD[3487:140302] 2---<NSThread: 0x604000065440>{number = 1, name = main}
2018-07-18 14:06:33.812720+0800 GCD[3487:140302] 2---<NSThread: 0x604000065440>{number = 1, name = main}
2018-07-18 14:06:35.813879+0800 GCD[3487:140302] 3---<NSThread: 0x604000065440>{number = 1, name = main}
2018-07-18 14:06:37.814369+0800 GCD[3487:140302] 3---<NSThread: 0x604000065440>{number = 1, name = main}
2018-07-18 14:06:37.814666+0800 GCD[3487:140302] SyncAndConcurrent---end
2盒犹、異步執(zhí)行 + 并發(fā)隊(duì)列
- 異步執(zhí)行具備開啟新線程的能力。且并發(fā)隊(duì)列可開啟多個(gè)線程,同時(shí)執(zhí)行多個(gè)任務(wù)急膀。因此除了當(dāng)前線程(主線程)沮协,系統(tǒng)又開啟了多個(gè)線程,并且任務(wù)是同時(shí)執(zhí)行的卓嫂。
- 因?yàn)槭遣l(fā)隊(duì)列慷暂,所以當(dāng)前線程中所有任務(wù)沒有等待,而是直接開啟了新線程晨雳,在新線程中執(zhí)行任務(wù)(異步執(zhí)行不做等待行瑞,可以繼續(xù)執(zhí)行任務(wù))。
//2.異步執(zhí)行 + 并發(fā)隊(duì)列
- (instancetype)initAsyncAndConcurrentDispatch {
if (self = [super init]) {
NSLog(@"currentThread---%@",[NSThread currentThread]);//打印當(dāng)前線程
NSLog(@"AsyncAndConcurrent---begin");
dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);//創(chuàng)建并發(fā)隊(duì)列
dispatch_async(queue, ^{//異步執(zhí)行
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)操作
NSLog(@"1---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
dispatch_async(queue, ^{//異步執(zhí)行
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)操作
NSLog(@"2---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
dispatch_async(queue, ^{//異步執(zhí)行
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)操作
NSLog(@"3---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
NSLog(@"AsyncAndConcurrent---end");
}
return self;
}
輸出結(jié)果:
2018-07-18 14:13:36.852829+0800 GCD[3487:140302] currentThread---<NSThread: 0x604000065440>{number = 1, name = main}
2018-07-18 14:13:36.853047+0800 GCD[3487:140302] AsyncAndConcurrent---begin
2018-07-18 14:13:36.853189+0800 GCD[3487:140302] AsyncAndConcurrent---end
2018-07-18 14:13:38.854025+0800 GCD[3487:140559] 2---<NSThread: 0x60400027cc40>{number = 4, name = (null)}
2018-07-18 14:13:38.854027+0800 GCD[3487:145869] 1---<NSThread: 0x600000462780>{number = 3, name = (null)}
2018-07-18 14:13:38.854025+0800 GCD[3487:145877] 3---<NSThread: 0x604000277c00>{number = 5, name = (null)}
2018-07-18 14:13:40.858188+0800 GCD[3487:145869] 1---<NSThread: 0x600000462780>{number = 3, name = (null)}
2018-07-18 14:13:40.858188+0800 GCD[3487:140559] 2---<NSThread: 0x60400027cc40>{number = 4, name = (null)}
2018-07-18 14:13:40.858288+0800 GCD[3487:145877] 3---<NSThread: 0x604000277c00>{number = 5, name = (null)}
3餐禁、同步執(zhí)行 + 串行隊(duì)列
- 同步執(zhí)行不具備開啟新線程的能力血久,因此所有任務(wù)都是在當(dāng)前線程(主線程)中執(zhí)行的。
- 因?yàn)槭谴嘘?duì)列帮非,所以任務(wù)是一個(gè)接一個(gè)按順序執(zhí)行氧吐,并且每次只有一個(gè)任務(wù)被執(zhí)行。
//3.同步執(zhí)行 + 串行隊(duì)列
- (instancetype)initSyncAndSerialDispatch {
if (self = [super init]) {
NSLog(@"currentThread---%@",[NSThread currentThread]);//打印當(dāng)前線程
NSLog(@"SyncAndSerial---begin");
dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);//創(chuàng)建串行隊(duì)列
dispatch_sync(queue, ^{
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)操作
NSLog(@"1---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
dispatch_sync(queue, ^{
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)操作
NSLog(@"2---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
dispatch_sync(queue, ^{
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)操作
NSLog(@"3---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
NSLog(@"SyncAndSerial---end");
}
return self;
}
輸出結(jié)果:
2018-07-18 14:18:52.586924+0800 GCD[3487:140302] currentThread---<NSThread: 0x604000065440>{number = 1, name = main}
2018-07-18 14:18:52.587135+0800 GCD[3487:140302] SyncAndSerial---begin
2018-07-18 14:18:54.587815+0800 GCD[3487:140302] 1---<NSThread: 0x604000065440>{number = 1, name = main}
2018-07-18 14:18:56.588782+0800 GCD[3487:140302] 1---<NSThread: 0x604000065440>{number = 1, name = main}
2018-07-18 14:18:58.590248+0800 GCD[3487:140302] 2---<NSThread: 0x604000065440>{number = 1, name = main}
2018-07-18 14:19:00.591183+0800 GCD[3487:140302] 2---<NSThread: 0x604000065440>{number = 1, name = main}
2018-07-18 14:19:02.591603+0800 GCD[3487:140302] 3---<NSThread: 0x604000065440>{number = 1, name = main}
2018-07-18 14:19:04.593199+0800 GCD[3487:140302] 3---<NSThread: 0x604000065440>{number = 1, name = main}
2018-07-18 14:19:04.593466+0800 GCD[3487:140302] SyncAndSerial---end
4末盔、異步執(zhí)行 + 串行隊(duì)列
- 異步執(zhí)行具備開啟新線程的能力副砍。但由于是串行隊(duì)列,只能開啟一個(gè)線程庄岖。因此除了當(dāng)前線程(主線程)豁翎,系統(tǒng)又開啟了一個(gè)線程。
- 因?yàn)槭谴嘘?duì)列隅忿,所以任務(wù)是一個(gè)接一個(gè)按順序執(zhí)行心剥,并且每次只有一個(gè)任務(wù)被執(zhí)行。但串行隊(duì)列中的所有任務(wù)都是在新開啟的線程中執(zhí)行的背桐。
//4.異步執(zhí)行 + 串行隊(duì)列
- (instancetype)initAsyncAndSerialDispatch {
if (self = [super init]) {
NSLog(@"currentThread---%@",[NSThread currentThread]);//打印當(dāng)前線程
NSLog(@"AsyncAndSerial---begin");
dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);//創(chuàng)建串行隊(duì)列
dispatch_async(queue, ^{
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)操作
NSLog(@"1---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
dispatch_async(queue, ^{
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)操作
NSLog(@"2---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
dispatch_async(queue, ^{
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)操作
NSLog(@"3---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
NSLog(@"AsyncAndSerial---end");
}
return self;
}
輸出結(jié)果:
2018-07-18 14:25:13.368635+0800 GCD[3787:154025] currentThread---<NSThread: 0x604000066400>{number = 1, name = main}
2018-07-18 14:25:13.368890+0800 GCD[3787:154025] AsyncAndSerial---begin
2018-07-18 14:25:13.369052+0800 GCD[3787:154025] AsyncAndSerial---end
2018-07-18 14:25:15.373476+0800 GCD[3787:154089] 1---<NSThread: 0x6000002709c0>{number = 3, name = (null)}
2018-07-18 14:25:17.377079+0800 GCD[3787:154089] 1---<NSThread: 0x6000002709c0>{number = 3, name = (null)}
2018-07-18 14:25:19.381357+0800 GCD[3787:154089] 2---<NSThread: 0x6000002709c0>{number = 3, name = (null)}
2018-07-18 14:25:21.382271+0800 GCD[3787:154089] 2---<NSThread: 0x6000002709c0>{number = 3, name = (null)}
2018-07-18 14:25:23.384662+0800 GCD[3787:154089] 3---<NSThread: 0x6000002709c0>{number = 3, name = (null)}
2018-07-18 14:25:25.386662+0800 GCD[3787:154089] 3---<NSThread: 0x6000002709c0>{number = 3, name = (null)}
5优烧、同步執(zhí)行 + 主隊(duì)列(會(huì)造成死鎖)
- 在主線程中使用同步執(zhí)行 + 主隊(duì)列會(huì)造成死鎖
//5.同步執(zhí)行 + 主隊(duì)列(會(huì)造成死鎖)
- (instancetype)initSyncAndMainDispatch {
if (self = [super init]) {
NSLog(@"currentThread---%@",[NSThread currentThread]);//打印當(dāng)前線程
NSLog(@"SyncAndMain---begin");
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)操作
NSLog(@"1---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
NSLog(@"SyncAndMain---end");
}
return self;
}
輸出結(jié)果:
2018-07-18 14:31:31.002501+0800 GCD[3787:154025] currentThread---<NSThread: 0x604000066400>{number = 1, name = main}
2018-07-18 14:31:31.002743+0800 GCD[3787:154025] SyncAndMain---begin
由此可以看出:
- 在主線程中使用同步執(zhí)行 + 主隊(duì)列,追加到主線程的任務(wù)1不再執(zhí)行了链峭,而且syncMain---end也沒有打印
- 死鎖原因:這是因?yàn)槲覀冊(cè)谥骶€程中添加同步操作時(shí)畦娄,同步操作要等主線程的任務(wù)執(zhí)行完成才開始執(zhí)行,此時(shí)同步操作處于等待狀態(tài)弊仪。而主線程任務(wù)中含有已經(jīng)添加的同步操作熙卡,而主線程只有等同步操作執(zhí)行完成才能繼續(xù)操作,而此時(shí)的同步操作處于等待狀態(tài)励饵,所以主線程會(huì)等待同步操作執(zhí)行完成才繼續(xù)執(zhí)行驳癌,從而兩者相互等待,以至于會(huì)造成線程死鎖役听。
解決死鎖的辦法:把需要在主隊(duì)列中同步執(zhí)行的任務(wù)放到其他線程中去颓鲜。
//同步執(zhí)行 + 主隊(duì)列(解決死鎖調(diào)用方法)
- (instancetype)initSyncAndMainDispatchResolve {
if (self = [super init]) {
NSLog(@"currentThread---%@",[NSThread currentThread]);//打印當(dāng)前線程
NSLog(@"SyncAndMain---begin");
//創(chuàng)建其他線程中調(diào)用同步執(zhí)行 + 主隊(duì)列
[NSThread detachNewThreadSelector:@selector(SyncMain) toTarget:self withObject:nil];
}
return self;
}
- (void)SyncMain {
NSLog(@"currentThread 4---%@",[NSThread currentThread]);//打印當(dāng)前線程
NSLog(@"SyncAndMain 4---begin");
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)操作
NSLog(@"1---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
dispatch_sync(queue, ^{
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)操作
NSLog(@"2---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
dispatch_sync(queue, ^{
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)操作
NSLog(@"2---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
NSLog(@"SyncAndMain---end");
}
輸出結(jié)果:
2018-07-18 14:38:07.108703+0800 GCD[4000:163392] currentThread---<NSThread: 0x60400006b600>{number = 1, name = main}
2018-07-18 14:38:07.108999+0800 GCD[4000:163392] SyncAndMain---begin
2018-07-18 14:38:07.110803+0800 GCD[4000:164570] currentThread 4---<NSThread: 0x600000468240>{number = 3, name = (null)}
2018-07-18 14:38:07.111920+0800 GCD[4000:164570] SyncAndMain 4---begin
2018-07-18 14:38:09.114080+0800 GCD[4000:163392] 1---<NSThread: 0x60400006b600>{number = 1, name = main}
2018-07-18 14:38:11.115053+0800 GCD[4000:163392] 1---<NSThread: 0x60400006b600>{number = 1, name = main}
2018-07-18 14:38:13.116707+0800 GCD[4000:163392] 2---<NSThread: 0x60400006b600>{number = 1, name = main}
2018-07-18 14:38:15.117198+0800 GCD[4000:163392] 2---<NSThread: 0x60400006b600>{number = 1, name = main}
2018-07-18 14:38:17.118623+0800 GCD[4000:163392] 2---<NSThread: 0x60400006b600>{number = 1, name = main}
2018-07-18 14:38:19.120149+0800 GCD[4000:163392] 2---<NSThread: 0x60400006b600>{number = 1, name = main}
2018-07-18 14:38:19.120473+0800 GCD[4000:164570] SyncAndMain---end
6表窘、異步執(zhí)行 + 主隊(duì)列
- 雖然異步執(zhí)行具備開啟線程的能力,但因?yàn)槭侵麝?duì)列甜滨,所以所有任務(wù)都是在當(dāng)前線程(主線程)中執(zhí)行的乐严,并沒有開啟新的線程。
- 因?yàn)槭谴嘘?duì)列衣摩,所以任務(wù)是一個(gè)接一個(gè)按順序執(zhí)行麦备,并且每次只有一個(gè)任務(wù)被執(zhí)行。
//6.異步執(zhí)行 + 主隊(duì)列
- (instancetype)initAsyncAndMainDispatch {
if (self = [super init]) {
NSLog(@"currentThread---%@",[NSThread currentThread]);//打印當(dāng)前線程
NSLog(@"AsyncAndMain---begin");
dispatch_queue_t queue = dispatch_get_main_queue(); //獲取主線程
dispatch_async(queue, ^{
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)線程
NSLog(@"1---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
dispatch_async(queue, ^{
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)線程
NSLog(@"2---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
dispatch_async(queue, ^{
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2]; //模擬耗時(shí)線程
NSLog(@"3---%@",[NSThread currentThread]); //打印當(dāng)前線程
}
});
NSLog(@"AsyncAndMain---end");
}
return self;
}
輸出結(jié)果:
2018-07-18 14:44:03.921354+0800 GCD[4125:168926] currentThread---<NSThread: 0x60000006ce00>{number = 1, name = main}
2018-07-18 14:44:03.921575+0800 GCD[4125:168926] AsyncAndMain---begin
2018-07-18 14:44:03.921763+0800 GCD[4125:168926] AsyncAndMain---end
2018-07-18 14:44:05.926029+0800 GCD[4125:168926] 1---<NSThread: 0x60000006ce00>{number = 1, name = main}
2018-07-18 14:44:07.928790+0800 GCD[4125:168926] 1---<NSThread: 0x60000006ce00>{number = 1, name = main}
2018-07-18 14:44:09.931443+0800 GCD[4125:168926] 2---<NSThread: 0x60000006ce00>{number = 1, name = main}
2018-07-18 14:44:11.933365+0800 GCD[4125:168926] 2---<NSThread: 0x60000006ce00>{number = 1, name = main}
2018-07-18 14:44:13.935818+0800 GCD[4125:168926] 3---<NSThread: 0x60000006ce00>{number = 1, name = main}
2018-07-18 14:44:15.937064+0800 GCD[4125:168926] 3---<NSThread: 0x60000006ce00>{number = 1, name = main}
7昭娩、同步執(zhí)行 + 全局并發(fā)隊(duì)列
由于全局并發(fā)隊(duì)列等同于普通并發(fā)隊(duì)列凛篙,所以該操作等同于同步執(zhí)行 + 并發(fā)隊(duì)列,請(qǐng)參考 1栏渺、同步執(zhí)行 + 并發(fā)隊(duì)列呛梆。
8、異步執(zhí)行 + 全局并發(fā)隊(duì)列
由于全局并發(fā)隊(duì)列等同于普通并發(fā)隊(duì)列磕诊,所以該操作等同于異步執(zhí)行 + 并發(fā)隊(duì)列填物,請(qǐng)參考 2、異步執(zhí)行 + 并發(fā)隊(duì)列霎终。
9滞磺、GCD柵欄方法:dispatch_barrier_async
- dispatch_barrier_async函數(shù)的作用是在進(jìn)程管理中起到一個(gè)柵欄的作用,它等待所有位于barrier函數(shù)之前的操作執(zhí)行完畢后執(zhí)行,并且在barrier函數(shù)執(zhí)行之后,barrier函數(shù)之后的操作才會(huì)得到執(zhí)行。
- 該函數(shù)需要配合并發(fā)隊(duì)列(
dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);
)使用莱褒。
//9.GCD柵欄方法
- (void)dispatchBarrier {
NSLog(@"currentThread --- %@",[NSThread currentThread]);
NSLog(@"dispatchBarrier --- Begin");
dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"1---%@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"2---%@",[NSThread currentThread]);
}
});
//柵欄方法
dispatch_barrier_async(queue, ^{
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"3---%@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"4---%@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"5---%@",[NSThread currentThread]);
}
});
NSLog(@"dispatchBarrier --- end");
}
輸出結(jié)果:
2018-07-18 14:59:21.577599+0800 GCD[4125:168926] currentThread --- <NSThread: 0x60000006ce00>{number = 1, name = main}
2018-07-18 14:59:21.577839+0800 GCD[4125:168926] dispatchBarrier --- Begin
2018-07-18 14:59:21.578039+0800 GCD[4125:168926] dispatchBarrier --- end
2018-07-18 14:59:23.581183+0800 GCD[4125:169172] 2---<NSThread: 0x604000273ec0>{number = 4, name = (null)}
2018-07-18 14:59:23.581191+0800 GCD[4125:180793] 1---<NSThread: 0x600000477880>{number = 3, name = (null)}
2018-07-18 14:59:25.585534+0800 GCD[4125:169172] 2---<NSThread: 0x604000273ec0>{number = 4, name = (null)}
2018-07-18 14:59:25.585605+0800 GCD[4125:180793] 1---<NSThread: 0x600000477880>{number = 3, name = (null)}
2018-07-18 14:59:27.589468+0800 GCD[4125:180793] 3---<NSThread: 0x600000477880>{number = 3, name = (null)}
2018-07-18 14:59:29.594449+0800 GCD[4125:180793] 3---<NSThread: 0x600000477880>{number = 3, name = (null)}
2018-07-18 14:59:31.599255+0800 GCD[4125:180793] 4---<NSThread: 0x600000477880>{number = 3, name = (null)}
2018-07-18 14:59:31.599255+0800 GCD[4125:169172] 5---<NSThread: 0x604000273ec0>{number = 4, name = (null)}
2018-07-18 14:59:33.603883+0800 GCD[4125:180793] 4---<NSThread: 0x600000477880>{number = 3, name = (null)}
2018-07-18 14:59:33.603883+0800 GCD[4125:169172] 5---<NSThread: 0x604000273ec0>{number = 4, name = (null)}
10击困、GCD延時(shí)執(zhí)行方法:dispatch_after
- dispatch_after函數(shù)可以實(shí)現(xiàn)在指定時(shí)間之后開始執(zhí)行某個(gè)任務(wù)。需要注意的是dispatch_after函數(shù)并不是在指定時(shí)間之后才開始執(zhí)行處理广凸,而是在指定時(shí)間之后將任務(wù)追加到主隊(duì)列中阅茶。嚴(yán)格來說,這個(gè)時(shí)間并不是絕對(duì)準(zhǔn)確的谅海,但想要大致延遲執(zhí)行任務(wù)脸哀,dispatch_after函數(shù)是很有效的。
//10.GCD延時(shí)執(zhí)行方法
- (void)dispatchAfter {
NSLog(@"currentThread---%@",[NSThread currentThread]); //打印當(dāng)前線程
NSLog(@"dispatchAfter---begin");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"after---%@",[NSThread currentThread]); //打印當(dāng)前線程
});
NSLog(@"dispatchAfter---end");
}
輸出結(jié)果:
2018-07-18 15:08:27.072470+0800 GCD[4125:168926] currentThread---<NSThread: 0x60000006ce00>{number = 1, name = main}
2018-07-18 15:08:27.072737+0800 GCD[4125:168926] dispatchAfter---begin
2018-07-18 15:08:27.072927+0800 GCD[4125:168926] dispatchAfter---end
2018-07-18 15:08:29.073087+0800 GCD[4125:168926] after---<NSThread: 0x60000006ce00>{number = 1, name = main}
11扭吁、GCD單例:dispatch_once
- 使用dispatch_once 函數(shù)能保證某段代碼在程序運(yùn)行過程中只被執(zhí)行一次撞蜂,并且即使在多線程的環(huán)境下,dispatch_once也可以保證線程安全侥袜。
#import "DispatchOnce.h"
static DispatchOnce * _onceManager;
@implementation DispatchOnce
//單例
+ (instancetype)dispatchOnceManager {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_onceManager = [[DispatchOnce alloc]init];
});
return _onceManager;
}
+ (instancetype)dispatchManager {
_onceManager = [[DispatchOnce alloc]init];
return _onceManager;
}
@end
//打印創(chuàng)建對(duì)象地址
DispatchOnce * one = [DispatchOnce dispatchOnceManager];
DispatchOnce * two = [DispatchOnce dispatchOnceManager];
DispatchOnce * three = [DispatchOnce dispatchManager];
DispatchOnce * four = [DispatchOnce dispatchManager];
NSLog(@"one :%@",one);
NSLog(@"two :%@",two);
NSLog(@"three:%@",three);
NSLog(@"four :%@",four);
輸出結(jié)果:
2018-07-18 15:12:01.385630+0800 GCD[4125:168926] one :<DispatchOnce: 0x60400001bfd0>
2018-07-18 15:12:01.385830+0800 GCD[4125:168926] two :<DispatchOnce: 0x60400001bfd0>
2018-07-18 15:12:01.385957+0800 GCD[4125:168926] three:<DispatchOnce: 0x60400001b6a0>
2018-07-18 15:12:01.386151+0800 GCD[4125:168926] four :<DispatchOnce: 0x60400001aad0>
12蝌诡、GCD快速迭代方法:dispatch_apply
- dispatch_apply按照指定的次數(shù)將指定的任務(wù)追加到指定的隊(duì)列中,并等待全部隊(duì)列執(zhí)行結(jié)束系馆。
- 因?yàn)槭窃诓l(fā)隊(duì)列中異步執(zhí)行任務(wù)送漠,所以各個(gè)任務(wù)的執(zhí)行時(shí)間長短不定,最后結(jié)束順序也不定由蘑。但是線程會(huì)等待dispatch_apply函數(shù)中全部任務(wù)執(zhí)行完畢才會(huì)繼續(xù)執(zhí)行其他任務(wù)闽寡。
//12.GCD 快速迭代方法:dispatch_apply
- (instancetype)initDispatchApplyManager {
if (self = [super init]) {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"apply---begin");
dispatch_apply(5, queue, ^(size_t index) {
NSLog(@"%ld --- %@",index,[NSThread currentThread]);
});
NSLog(@"apply---end");
}
return self;
}
輸出結(jié)果:
2018-07-18 15:18:23.522423+0800 GCD[4125:168926] apply---begin
2018-07-18 15:18:23.524855+0800 GCD[4125:168926] 0 --- <NSThread: 0x60000006ce00>{number = 1, name = main}
2018-07-18 15:18:23.524875+0800 GCD[4125:194598] 1 --- <NSThread: 0x604000274b00>{number = 5, name = (null)}
2018-07-18 15:18:23.524926+0800 GCD[4125:180800] 2 --- <NSThread: 0x600000478000>{number = 6, name = (null)}
2018-07-18 15:18:23.524982+0800 GCD[4125:194608] 3 --- <NSThread: 0x604000271b80>{number = 7, name = (null)}
2018-07-18 15:18:23.525190+0800 GCD[4125:168926] 4 --- <NSThread: 0x60000006ce00>{number = 1, name = main}
2018-07-18 15:18:23.525362+0800 GCD[4125:168926] apply---end
13、GCD隊(duì)列組:dispatch_group
如果我們?cè)谝粋€(gè)線程中異步執(zhí)行幾個(gè)耗時(shí)操作尼酿,但我們想等這幾個(gè)耗時(shí)操作都完成之后再去執(zhí)行其他操作爷狈,這時(shí)候我們就可以用到隊(duì)列組dispatch_group了。
使用方式:調(diào)用隊(duì)列組的 dispatch_group_async
先把任務(wù)放到隊(duì)列中裳擎,然后將隊(duì)列放入隊(duì)列組中涎永。或者使用隊(duì)列組的dispatch_group_enter
鹿响、dispatch_group_leave
組合來實(shí)現(xiàn)dispatch_group_async
羡微。或者調(diào)用隊(duì)列組的 dispatch_group_notify
回到指定線程執(zhí)行任務(wù)惶我÷杈螅或者使用dispatch_group_wait
回到當(dāng)前線程繼續(xù)向下執(zhí)行(會(huì)阻塞當(dāng)前線程)
dispatch_group_notify
- (IBAction)dispatch_group_notify:(id)sender {
NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印當(dāng)前線程
NSLog(@"group---begin");
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_group_async(group, globalQueue, ^{
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模擬耗時(shí)操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印當(dāng)前線程
}
});
dispatch_group_async(group, globalQueue, ^{
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模擬耗時(shí)操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印當(dāng)前線程
}
});
dispatch_group_notify(group, mainQueue, ^{
// 等前面的異步任務(wù)1、任務(wù)2都執(zhí)行完畢后绸贡,回到主線程執(zhí)行下邊任務(wù)
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模擬耗時(shí)操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印當(dāng)前線程
}
NSLog(@"group---end");
});
}
輸出結(jié)果:
2018-07-18 15:40:04.310925+0800 GCD[4125:168926] currentThread---<NSThread: 0x60000006ce00>{number = 1, name = main}
2018-07-18 15:40:04.311191+0800 GCD[4125:168926] group---begin
2018-07-18 15:40:06.316638+0800 GCD[4125:208985] 1---<NSThread: 0x6000004666c0>{number = 8, name = (null)}
2018-07-18 15:40:06.316645+0800 GCD[4125:180800] 2---<NSThread: 0x600000478000>{number = 6, name = (null)}
2018-07-18 15:40:08.319994+0800 GCD[4125:180800] 2---<NSThread: 0x600000478000>{number = 6, name = (null)}
2018-07-18 15:40:08.320003+0800 GCD[4125:208985] 1---<NSThread: 0x6000004666c0>{number = 8, name = (null)}
2018-07-18 15:40:10.321659+0800 GCD[4125:168926] 3---<NSThread: 0x60000006ce00>{number = 1, name = main}
2018-07-18 15:40:12.322667+0800 GCD[4125:168926] 3---<NSThread: 0x60000006ce00>{number = 1, name = main}
2018-07-18 15:40:12.323029+0800 GCD[4125:168926] group---end
- 監(jiān)聽 group 中任務(wù)的完成狀態(tài)盯蝴,當(dāng)所有的任務(wù)都執(zhí)行完成后,追加任務(wù)到 group 中听怕,并執(zhí)行任務(wù)捧挺。
- 從dispatch_group_notify相關(guān)代碼運(yùn)行輸出結(jié)果可以看出:
當(dāng)所有任務(wù)都執(zhí)行完成之后,才執(zhí)行dispatch_group_notify block 中的任務(wù)尿瞭。
dispatch_group_wait
- (IBAction)dispatch_group_wait:(id)sender {
NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印當(dāng)前線程
NSLog(@"group---begin");
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_async(group, globalQueue, ^{
// 追加任務(wù)1
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模擬耗時(shí)操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印當(dāng)前線程
}
});
dispatch_group_async(group, globalQueue, ^{
// 追加任務(wù)2
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模擬耗時(shí)操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印當(dāng)前線程
}
});
//等待上面的任務(wù)全部完成后闽烙,會(huì)往下繼續(xù)執(zhí)行(會(huì)阻塞當(dāng)前線程)
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"group---end");
}
輸出結(jié)果:
2018-07-18 15:46:21.438719+0800 GCD[5117:214014] currentThread---<NSThread: 0x600000260d80>{number = 1, name = main}
2018-07-18 15:46:21.439135+0800 GCD[5117:214014] group---begin
2018-07-18 15:46:23.440102+0800 GCD[5117:214604] 1---<NSThread: 0x60400046d440>{number = 4, name = (null)}
2018-07-18 15:46:23.440101+0800 GCD[5117:214057] 2---<NSThread: 0x600000666f00>{number = 3, name = (null)}
2018-07-18 15:46:25.446875+0800 GCD[5117:214057] 2---<NSThread: 0x600000666f00>{number = 3, name = (null)}
2018-07-18 15:46:25.447304+0800 GCD[5117:214604] 1---<NSThread: 0x60400046d440>{number = 4, name = (null)}
2018-07-18 15:46:25.453273+0800 GCD[5117:214014] group---end
- dispatch_group_wait會(huì)暫停當(dāng)前線程(阻塞當(dāng)前線程),等待指定的 group 中的任務(wù)執(zhí)行完成后声搁,才會(huì)往下繼續(xù)執(zhí)行鸣峭。
dispatch_group_enter、dispatch_group_leave
- (IBAction)dispatch_groupClick:(id)sender {
NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印當(dāng)前線程
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, ^{
// 追加任務(wù)1
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模擬耗時(shí)操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印當(dāng)前線程
}
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
// 追加任務(wù)2
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模擬耗時(shí)操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印當(dāng)前線程
}
dispatch_group_leave(group);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 等前面的異步操作都執(zhí)行完畢后酥艳,回到主線程.
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模擬耗時(shí)操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印當(dāng)前線程
}
NSLog(@"group---end");
});
// // 等待上面的任務(wù)全部完成后摊溶,會(huì)往下繼續(xù)執(zhí)行(會(huì)阻塞當(dāng)前線程)
// dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
// NSLog(@"group---end");
}
輸出結(jié)果:
2018-07-18 15:52:12.940112+0800 GCD[5242:219381] currentThread---<NSThread: 0x600000069200>{number = 1, name = main}
2018-07-18 15:52:12.940382+0800 GCD[5242:219381] group---begin
2018-07-18 15:52:14.946018+0800 GCD[5242:219651] 2---<NSThread: 0x600000469500>{number = 3, name = (null)}
2018-07-18 15:52:14.946018+0800 GCD[5242:219432] 1---<NSThread: 0x6000004762c0>{number = 4, name = (null)}
2018-07-18 15:52:16.951382+0800 GCD[5242:219432] 1---<NSThread: 0x6000004762c0>{number = 4, name = (null)}
2018-07-18 15:52:16.951397+0800 GCD[5242:219651] 2---<NSThread: 0x600000469500>{number = 3, name = (null)}
2018-07-18 15:52:18.953450+0800 GCD[5242:219381] 3---<NSThread: 0x600000069200>{number = 1, name = main}
2018-07-18 15:52:20.954745+0800 GCD[5242:219381] 3---<NSThread: 0x600000069200>{number = 1, name = main}
2018-07-18 15:52:20.954954+0800 GCD[5242:219381] group---end
- dispatch_group_enter 標(biāo)志著一個(gè)任務(wù)追加到 group,執(zhí)行一次充石,相當(dāng)于 group 中未執(zhí)行完畢任務(wù)數(shù)+1莫换。
- dispatch_group_leave 標(biāo)志著一個(gè)任務(wù)離開了 group,執(zhí)行一次骤铃,相當(dāng)于 group 中未執(zhí)行完畢任務(wù)數(shù)-1拉岁。
- 當(dāng) group 中未執(zhí)行完畢任務(wù)數(shù)為0的時(shí)候,才會(huì)使dispatch_group_wait解除阻塞惰爬,以及執(zhí)行追加到dispatch_group_notify中的任務(wù)喊暖。
- 從dispatch_group_enter、dispatch_group_leave相關(guān)代碼運(yùn)行結(jié)果中可以看出:當(dāng)所有任務(wù)執(zhí)行完成之后撕瞧,才執(zhí)行 dispatch_group_notify 中的任務(wù)陵叽。這里的dispatch_group_enter狞尔、dispatch_group_leave組合,其實(shí)等同于dispatch_group_async巩掺。
14偏序、GCD信號(hào)量:dispatch_semaphore
- 信號(hào)量就是一種可用來控制訪問資源的數(shù)量的標(biāo)識(shí),設(shè)定了一個(gè)信號(hào)量胖替,在線程訪問之前研儒,加上信號(hào)量的處理,則可告知系統(tǒng)按照我們指定的信號(hào)量數(shù)量來執(zhí)行多個(gè)線程独令。
- 類似鎖機(jī)制端朵,只不過信號(hào)量都是系統(tǒng)幫助我們處理了,我們只需要在執(zhí)行線程之前燃箭,設(shè)定一個(gè)信號(hào)量值冲呢,并且在使用時(shí),加上信號(hào)量處理方法就行了遍膜。
Dispatch Semaphore 提供了三個(gè)函數(shù):
-
dispatch_semaphore_create
:創(chuàng)建一個(gè)Semaphore并初始化信號(hào)的總量 -
dispatch_semaphore_signal
:發(fā)送一個(gè)信號(hào)碗硬,讓信號(hào)總量加1 -
dispatch_semaphore_wait
:可以使總信號(hào)量減1,當(dāng)信號(hào)總量為0時(shí)就會(huì)一直等待(阻塞所在線程)瓢颅,否則就可以正常執(zhí)行恩尾。
- (IBAction)useClick:(id)sender {
NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印當(dāng)前線程
NSLog(@"semaphore---begin");
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block NSInteger num = 0;
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:2]; // 模擬耗時(shí)操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印當(dāng)前線程
num = 1;
dispatch_semaphore_signal(semaphore);
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"semaphore---end,num = %ld",num);
}
輸出結(jié)果:
2018-07-18 16:05:37.412573+0800 GCD[5472:229493] currentThread---<NSThread: 0x60400007cdc0>{number = 1, name = main}
2018-07-18 16:05:37.412940+0800 GCD[5472:229493] semaphore---begin
2018-07-18 16:05:39.417126+0800 GCD[5472:229532] 1---<NSThread: 0x60000007e080>{number = 3, name = (null)}
2018-07-18 16:05:39.417295+0800 GCD[5472:229493] semaphore---end,num = 1
- 異步執(zhí)行不會(huì)做任何等待,可以繼續(xù)執(zhí)行任務(wù)挽懦。異步執(zhí)行將任務(wù)1追加到隊(duì)列之后翰意,不做等待,接著執(zhí)行dispatch_semaphore_wait方法信柿。此時(shí) semaphore == 0冀偶,當(dāng)前線程進(jìn)入等待狀態(tài)。然后渔嚷,異步任務(wù)1開始執(zhí)行进鸠。任務(wù)1執(zhí)行到dispatch_semaphore_signal之后,此時(shí)總信號(hào)量 semaphore == 1形病,dispatch_semaphore_wait方法使總信號(hào)量減1客年,正在被阻塞的線程(主線程)恢復(fù)繼續(xù)執(zhí)行。最后打印semaphore---end,number = 1漠吻。這樣就實(shí)現(xiàn)了線程同步量瓜,將異步執(zhí)行任務(wù)轉(zhuǎn)換為同步執(zhí)行任務(wù)。
- Dispatch Semaphore 在實(shí)際開發(fā)中主要用于:保持線程同步途乃,將異步執(zhí)行任務(wù)轉(zhuǎn)換為同步執(zhí)行任務(wù)绍傲;保證線程安全,為線程加鎖耍共。
15烫饼、取消GCD任務(wù)兩種方法:
- 第一種:iOS8之后可以調(diào)用dispatch_block_cancel來取消(需要注意必須用dispatch_block_create創(chuàng)建dispatch_block_t)猎塞,dispatch_block_cancel也只能取消尚未執(zhí)行的任務(wù),對(duì)正在執(zhí)行的任務(wù)不起作用枫弟。
- 第二種:定義外部變量邢享,用于標(biāo)記block是否需要取消鹏往,該方法是模擬NSOperation淡诗,在執(zhí)行block前先檢查isCancelled = YES ?在block中及時(shí)的檢測(cè)標(biāo)記變量伊履,當(dāng)發(fā)現(xiàn)需要取消時(shí)韩容,終止后續(xù)操作(如直接返回return)。
Demo地址:GCD
「歡迎指正交流」0_0