隊列是FIFO梦谜,先進先出原則
原則上丘跌,GCD只有兩種隊列,串行隊列
和并發(fā)隊列
唁桩。
全局隊列
是系統(tǒng)提供的一個并發(fā)隊列闭树,主隊列
是一個特殊的串行隊列,這里單獨分出來介紹而已荒澡。
1.串行隊列
串行隊列:放到該隊列上的任務串行執(zhí)行
dispatch_queue_t serailQueue= dispatch_queue_create("com.queue.serialQueue", DISPATCH_QUEUE_SERIAL);
參數1:隊列的標示
參數2:隊列的類型,NULL代表串行隊列,DISPATCH_QUEUE_SERIAL代表串行隊列 DISPATCH_QUEUE_CONCURRENT代表并行隊列
①串行隊列报辱,同步任務
特點:有順序執(zhí)行,不開辟線程
應用場景:FMDB,同步任務,保證數據安全
②串行隊列单山,異步任務
特點:在開辟的子線程中順序執(zhí)行,并且只開辟一條線程!
應用場景:耗時操作,有嚴格操作順序,比如付費網站下載圖片(登錄->付費->下載)
2.并發(fā)隊列
并發(fā)隊列碍现,必須自己寫,不能寫NULL
dispatch_queue_t concurrentQueue= dispatch_queue_create("com.queue.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
①并發(fā)隊列米奸,同步任務
特點:沒有開辟新線程昼接,同時是按照順序
應用場景:開發(fā)中幾乎不用
②并發(fā)隊列,異步任務
特點:會開線程,開N條,表示不固定,因為我們的線程循環(huán)利用的功能 沒有順序.
應用場景:多路下載
3.全局隊列和并發(fā)隊列執(zhí)行效果一樣悴晰,通常我們說的并發(fā)隊列是程序員自己創(chuàng)建的慢睡,而全局隊列是由系統(tǒng)提供的
特點:任務可以同時執(zhí)行逐工,這樣可以提高程序的運行效率.
①全局隊列,同步任務
特點:沒有開辟新線程漂辐,任務按照順序執(zhí)行
應用場景:開發(fā)中幾乎不用
②全局隊列泪喊,異步任務
特點:會開線程,開N條,表示不固定,因為我們的線程循環(huán)利用的功能,沒有順序者吁。
應用場景:多路下載
4.主隊列
GCD自帶的一種特殊的串行隊列窘俺,
永遠在主線程工作,所有放在主隊列中的任務复凳,都會放到主線程中執(zhí)行瘤泪。這個是蘋果給開發(fā)人員提供回到主線程做事的一種機制。
可使用dispatch_get_main_queue()獲得主隊列
①主隊列育八,同步任務
特點:主隊列对途,只有在主線程空閑的時候,才能調度里面的任務髓棋,會造成死鎖
②主隊列实檀,異步任務
應用場景:回到主線程做事,一般是做和UI相關的工作按声。
同步執(zhí)行 + 主隊列
同步執(zhí)行 + 主隊列在不同線程中調用結果也不一樣膳犹,在主線程中調用會出現死鎖,而在其他線程中不會卡住也不開啟新線程签则,執(zhí)行完一個任務须床,再執(zhí)行下一個任務。
- (void)syncMain {
NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印當前線程
NSLog(@"syncMain---begin");
// 1.獲取主隊列
dispatch_queue_t queue = dispatch_get_main_queue();
// 2.添加同步任務
dispatch_sync(queue, ^{
// 追加任務1
for(inti = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模擬耗時操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印當前線程
}
});
dispatch_sync(queue, ^{
// 追加任務2
for(inti = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模擬耗時操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印當前線程
}
});
dispatch_sync(queue, ^{
// 追加任務3
for(inti = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模擬耗時操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印當前線程
}
});
NSLog(@"syncMain---end");
}
------------------輸出結果----------------
currentThread---<NSThread: 0x600000410680>{number = 1, name = main}
syncMain---begin
------------------輸出結果----------------
在同步執(zhí)行 + 主隊列可以發(fā)現:
在主線程中使用同步執(zhí)行 + 主隊列渐裂,追加到主線程的任務1豺旬、任務2、任務3都不再執(zhí)行了柒凉,而且syncMain---end也沒有打印族阅,在XCode 還會報崩潰Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
。這是為什么呢膝捞?
這是因為我們在主線程中執(zhí)行syncMain方法坦刀,相當于把syncMain任務放到了主線程的隊列中。而同步執(zhí)行會等待當前隊列中的任務執(zhí)行完畢蔬咬,才會接著執(zhí)行求泰。那么當我們把任務1追加到主隊列中,任務1就在等待主線程處理完syncMain任務计盒。而syncMain任務需要等待任務1執(zhí)行完畢渴频,才能接著執(zhí)行。
那么北启,現在的情況就是syncMain任務和任務1都在等對方執(zhí)行完畢卜朗。這樣大家互相等待拔第,所以就卡住了,所以我們的任務執(zhí)行不了场钉,而且syncMain---end也沒有打印蚊俺。
如果不在主線程,而是在其他線程中調用同步執(zhí)行 + 主隊列
特點:不會開啟新線程逛万,執(zhí)行完一個任務泳猬,再執(zhí)行下一個任務
還是上面代碼,我們使用 NSThread 的 detachNewThreadSelector 方法會創(chuàng)建線程宇植,并自動啟動線程執(zhí)行 selector 任務
// 新建線程執(zhí)行 syncMain 方法
[NSThread detachNewThreadSelector:@selector(syncMain) toTarget:self withObject:nil];
------------------輸出結果----------------
currentThread---<NSThread: 0x600002fea9c0>{number = 6, name = (null)}
syncMain---begin
1---<NSThread: 0x600002fac740>{number = 1, name = main}
1---<NSThread: 0x600002fac740>{number = 1, name = main}
2---<NSThread: 0x600002fac740>{number = 1, name = main}
2---<NSThread: 0x600002fac740>{number = 1, name = main}
3---<NSThread: 0x600002fac740>{number = 1, name = main}
3---<NSThread: 0x600002fac740>{number = 1, name = main}
syncMain---end
------------------輸出結果----------------
在其他線程中使用同步執(zhí)行 + 主隊列可看到:
所有任務都是在主線程(非當前線程)中執(zhí)行的得封,沒有開啟新的線程(所有放在主隊列中的任務,都會放到主線程中執(zhí)行)指郁。
所有任務都在打印的syncMain---begin和syncMain---end之間執(zhí)行(同步任務需要等待隊列的任務執(zhí)行結束)忙上。
任務是按順序執(zhí)行的(主隊列是串行隊列,每次只有一個任務被執(zhí)行闲坎,任務一個接一個按順序執(zhí)行)疫粥。
因為syncMain 任務放到了其他線程里,而任務1腰懂、任務2梗逮、任務3都在追加到主隊列中,都會在主線程中執(zhí)行绣溜。syncMain 任務在其他線程中執(zhí)行到追加任務1到主隊列中库糠,因為主隊列現在沒有正在執(zhí)行的任務,所以涮毫,會直接執(zhí)行主隊列的任務1,等任務1執(zhí)行完畢贷屎,再接著執(zhí)行任務2罢防、任務3。所以這里不會卡住線程唉侄。
總結:
- 任務的優(yōu)先級比隊列優(yōu)先級高咒吐,所以我們在隊列和任務的各種組合的時候,首先要看我們的任務属划。
- 開不開線程,由任務決定
- 異步才有開辟線程的能力恬叹,同步沒有開辟線程的能力
- 異步是在其它線程上執(zhí)行,同步是在當前線程上執(zhí)行