1.概念相關(guān)
1.1 GCD(Grand Central Dispatch)是基于C語(yǔ)言開(kāi)發(fā)的多線程開(kāi)發(fā)技術(shù)(其它多線程技術(shù)后面再續(xù)),完全面向過(guò)程,使用起來(lái)也是最簡(jiǎn)單的,主要是適應(yīng)當(dāng)今多核并行運(yùn)算需求下提出的一套解決方案。比如說(shuō)在智能手機(jī)剛問(wèn)世的那個(gè)年代,打開(kāi)手機(jī)QQ,當(dāng)此時(shí)有了其它應(yīng)用需要被啟動(dòng)的時(shí)候,此時(shí)必須把QQ關(guān)掉才能打開(kāi)你想要啟動(dòng)的應(yīng)用。所以在這種需求背景下,偉大的GCD技術(shù)應(yīng)運(yùn)而生;
1.2 隊(duì)列,遵循先進(jìn)先出原則(FIFO),GCD提供的隊(duì)列有:串行隊(duì)列、并行隊(duì)列、主隊(duì)列、全局隊(duì)列;
-
1.3 隊(duì)列特點(diǎn):
- 串行隊(duì)列SerialQueue:只有一個(gè)線程,按加入隊(duì)列先后順序執(zhí)行;
- 并行隊(duì)列ConcurrentQueue:有多個(gè)線程,同時(shí)執(zhí)行,不等待;
- 主隊(duì)列MainQueue: 一定在線程中執(zhí)行,
- 全局隊(duì)列GlobalQueue:有多個(gè)線程,同時(shí)執(zhí)行,不等待;
-
1.4 任務(wù)執(zhí)行方式與特征:
- 同步執(zhí)行Sync:當(dāng)前線程+等待上一個(gè)任務(wù)完成再執(zhí)行當(dāng)前任務(wù)。
- 異步執(zhí)行Async:子線程+同時(shí)執(zhí)行每一個(gè)子線程的任務(wù)。
2.隊(duì)列任務(wù)組合方式
-
2.1 組合方式:
- 并行隊(duì)列 + 異步執(zhí)行 = 多個(gè)任務(wù)同時(shí)執(zhí)行 + 子線程執(zhí)行;
- 串行隊(duì)列 + 異步執(zhí)行 = 多個(gè)任務(wù)順序執(zhí)行 + 子線程執(zhí)行;
- 全局隊(duì)列 + 異步執(zhí)行 -> 子線程執(zhí)行+同時(shí)執(zhí)行
- 主隊(duì)列 + 異步執(zhí)行 -> 回到主線程方式二
- 串行隊(duì)列 + 同步執(zhí)行(很少使用) = 任務(wù)順序執(zhí)行 + 主線程執(zhí)行
- 并行隊(duì)列 + 同步執(zhí)行(不用該組合) = 任務(wù)順序執(zhí)行 + 主線程執(zhí)行
- 主隊(duì)列 + 同步執(zhí)行 -> 死鎖(兩個(gè)任務(wù)處于相互等待)
-
2.2 demo演示:
-
并行隊(duì)列 + 異步執(zhí)行:
并行隊(duì)列 + 異步執(zhí)行.png
并行隊(duì)列 + 異步執(zhí)行l(wèi)og.png -
串行隊(duì)列 + 異步執(zhí)行:
串行隊(duì)列 + 異步執(zhí)行.png
-
串行隊(duì)列 + 異步執(zhí)行l(wèi)og.png
-
全局隊(duì)列 + 異步執(zhí)行:
全局隊(duì)列 + 異步執(zhí)行.png
全局隊(duì)列 + 異步執(zhí)行l(wèi)og.png
-
主隊(duì)列 + 異步執(zhí)行:
主隊(duì)列 + 異步執(zhí)行.png
主隊(duì)列 + 異步執(zhí)行l(wèi)og.png
-
串行隊(duì)列 + 同步執(zhí)行:
串行隊(duì)列 + 同步執(zhí)行.png
串行隊(duì)列 + 同步執(zhí)行l(wèi)og.png
-
并行隊(duì)列 + 同步執(zhí)行:
并行隊(duì)列 + 同步執(zhí)行.png
并行隊(duì)列 + 同步執(zhí)行l(wèi)og.png
-
主隊(duì)列 + 同步執(zhí)行:
主隊(duì)列 + 同步執(zhí)行.png
主隊(duì)列 + 同步執(zhí)行l(wèi)og(死鎖).png
3.其它API
- 3.1
dispatch_set_target_queue
: 我們都知道隊(duì)列都是有優(yōu)先級(jí)的,當(dāng)不設(shè)置優(yōu)先級(jí)的時(shí)候,系統(tǒng)都采用了默認(rèn)優(yōu)先級(jí)的線程,當(dāng)如果在某處想修改優(yōu)先級(jí)的話(huà)就需要用到dispatch_set_target_queue
,使用方法如下:
dispatch_queue_t mySerialQueue = dispatch_queue_create("com.helloWorld", NULL);
dispatch_queue_t myGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_set_target_queue(mySerialQueue, myGlobalQueue);// 第一個(gè)參數(shù)為需要修改優(yōu)先級(jí)的隊(duì)列,第二個(gè)為需要修改成什么樣的隊(duì)列
// 注意:第一個(gè)參數(shù)不可使用全局隊(duì)列與主隊(duì)列
- 3.2
dispatch_after
: 顧名思義就是指定時(shí)間后執(zhí)行某個(gè)任務(wù),說(shuō)白了就是睡一段時(shí)間,使用方法如下:
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC);
dispatch_after(time, dispatch_get_main_queue(), ^{
NSLog(@"hello world");
});
- 3.3
dispatch_group
:在該隊(duì)列中多個(gè)任務(wù)完成后需要執(zhí)行某個(gè)任務(wù)時(shí),可以用group
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
NSLog(@"0");
});
dispatch_group_async(group, queue, ^{
NSLog(@"1");
});
dispatch_group_async(group, queue, ^{
NSLog(@"2");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"game over");
});
執(zhí)行結(jié)果如下:
0
1
2
game over
- 3.4
dispatch_barrier
: 主要用來(lái)處理“數(shù)據(jù)競(jìng)爭(zhēng)”問(wèn)題,當(dāng)有多個(gè)線程同時(shí)需要讀寫(xiě)某個(gè)數(shù)據(jù)的時(shí)候,為了防止獲取到的數(shù)據(jù)是一個(gè)舊數(shù)據(jù),可用此解決。如果在下面代碼,當(dāng)想在reading2
后修改某個(gè)數(shù)據(jù),此時(shí)正確姿勢(shì)應(yīng)該使用dispatch_barrier
來(lái)保證
reading2
后面讀取到的是最新數(shù)據(jù):
dispatch_queue_t myConcurrentQueue = dispatch_queue_create("com.barrier", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(myConcurrentQueue, ^{
NSLog(@"reading0");
});
dispatch_async(myConcurrentQueue, ^{
NSLog(@"reading1");
});
dispatch_async(myConcurrentQueue, ^{
NSLog(@"reading2");
});
dispatch_async(myConcurrentQueue, ^{
NSLog(@"reading3");
});
// 為保證讀寫(xiě)的正確性,應(yīng)在需要修改的代碼插入dispatch_barrier,如下:
dispatch_queue_t myConcurrentQueue = dispatch_queue_create("com.barrier", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(myConcurrentQueue, ^{
NSLog(@"reading0");
});
dispatch_async(myConcurrentQueue, ^{
NSLog(@"reading1");
});
dispatch_async(myConcurrentQueue, ^{
NSLog(@"reading2");
});
dispatch_barrier_async(myConcurrentQueue, ^{
NSLog(@"writing");
});
dispatch_async(myConcurrentQueue, ^{
NSLog(@"reading3");
});