兩個(gè)特殊隊(duì)列:
dispatch_get_main_queue()主隊(duì)列,串行隊(duì)列。
dispatch_get_global_queue(0, 0)全局并發(fā)隊(duì)列。這個(gè)隊(duì)列是系統(tǒng)維護(hù)的,會(huì)被用來(lái)處理很多系統(tǒng)級(jí)事件。
最簡(jiǎn)單的block:
dispatch_block_t這是個(gè)無(wú)參無(wú)返回值的block。
關(guān)于同步異步函數(shù):
dispatch_sync同步函數(shù)沒(méi)有開(kāi)啟線程的能力。所有的代碼都會(huì)在當(dāng)前線程立即執(zhí)行。
dispatch_async異步函數(shù)有開(kāi)啟線程的能力。
關(guān)于串行并行隊(duì)列:
dispatch_queue_create(0,0)
DISPATCH_CURRENT_QUEUE_LABEL串行隊(duì)列遵循FIFO原則,先進(jìn)先出。
DISPATCH_QUEUE_CONCURRENT并行隊(duì)列,之間不會(huì)相互影響會(huì)各自執(zhí)行。執(zhí)行順序與加入隊(duì)列順序有關(guān)。
排列組合之后,就有了這么一套機(jī)制,如下圖:

知識(shí)點(diǎn)較多的主要是同步函數(shù)串行隊(duì)列。產(chǎn)生堵塞的原因本質(zhì)上還是任務(wù)執(zhí)行順序的問(wèn)題。如下經(jīng)典代碼就會(huì)產(chǎn)生堵塞(死鎖):
// 同步隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("xxx", DISPATCH_QUEUE_SERIAL);
NSLog(@"1");
// 異步函數(shù)
dispatch_async(queue, ^{
NSLog(@"2");
// 同步
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
分析圖如下

本質(zhì)上,異步函數(shù)里的代碼是加入隊(duì)列后,按順序執(zhí)行的。所以會(huì)執(zhí)行2->同步->4。
但是,同步函數(shù)的性質(zhì)又會(huì)讓代碼立即執(zhí)行。所以在執(zhí)行同步函數(shù)的時(shí)候,會(huì)要求立即執(zhí)行log3。
但是log3這個(gè)任務(wù)因?yàn)榇嘘?duì)列順序的原因,必須等到log4執(zhí)行完畢之后才會(huì)執(zhí)行。
此時(shí)發(fā)生了log4與log3相互等待的情況,而產(chǎn)生了堵塞。
這只是同步串行會(huì)出現(xiàn)問(wèn)題的一種方式。單純的在主線程中使用同步串行,是沒(méi)有問(wèn)題,而且借助其一定會(huì)按順序執(zhí)行的特性。還能達(dá)到某些鎖的功能:如經(jīng)典的購(gòu)票問(wèn)題:
- (void)saleTickes {
self.tickets = 20;
_queue = dispatch_queue_create("xxx", DISPATCH_QUEUE_SERIAL);
while (self.tickets > 0) {
// 使用串行隊(duì)列,同步任務(wù)賣(mài)票
dispatch_sync(_queue, ^{
// 檢查票數(shù)
if (self.tickets > 0) {
self.tickets--;
}
});
}
}
代碼很簡(jiǎn)單,不需要解釋。這個(gè)demo只是說(shuō)明同步串行的效果。其實(shí)這段代碼意義不大,因?yàn)閷?shí)現(xiàn)購(gòu)票必定要在異步并發(fā)隊(duì)列里才會(huì)更好的達(dá)到效果。如下:
- (void)saleTickes {
NSLock *lock = [NSLock new];
_tickets = 20;
_queue = dispatch_queue_create("Cooci", DISPATCH_QUEUE_CONCURRENT);
while (self.tickets > 0) {
[lock lock];
dispatch_async(_queue, ^{
// 檢查票數(shù)
if (self.tickets > 0) {
self.tickets--;
NSLog(@"還剩 %zd %@", self.tickets, [NSThread currentThread]);
} else {
NSLog(@"沒(méi)有票了");
}
[lock unlock];
});
}
}
柵欄函數(shù):
柵欄函數(shù)的用法,多用于控制并發(fā)隊(duì)列的執(zhí)行時(shí)機(jī),并且只用于控制唯一一個(gè)并發(fā)隊(duì)列(控制串行隊(duì)列沒(méi)有意義)。其中的barrier單詞很好的說(shuō)明了他的作用。就是個(gè)擋路的:在我之前的任務(wù)都要被我擋住,等我執(zhí)行完畢之后,之后的任務(wù)才會(huì)執(zhí)行。
dispatch_barrier_sync同步柵欄函數(shù):不僅僅會(huì)阻擋 并發(fā)隊(duì)列的任務(wù),還會(huì)阻擋 當(dāng)前線程的任務(wù) 。直至該函數(shù) 之前的并發(fā)隊(duì)列任務(wù) 執(zhí)行完畢后,才會(huì)繼續(xù)執(zhí)行 當(dāng)前線程的任務(wù) 與 后面的并發(fā)任務(wù) 。
dispatch_barrier_async異步柵欄函數(shù):只阻擋 并發(fā)隊(duì)列的任務(wù) 。不會(huì)阻擋 當(dāng)前線程的任務(wù) 。所以 當(dāng)前線程的任務(wù) ,都會(huì)比 所有的并發(fā)隊(duì)列的任務(wù) 先執(zhí)行。
demo如下:就不解釋了
- (void)demo2{
dispatch_queue_t concurrentQueue = dispatch_queue_create("cooci", DISPATCH_QUEUE_CONCURRENT);
/* 1.異步函數(shù) */
dispatch_async(concurrentQueue, ^{
for (NSUInteger i = 0; i < 5; i++) {
NSLog(@"download1-%zd-%@",i,[NSThread currentThread]);
}
});
dispatch_async(concurrentQueue, ^{
for (NSUInteger i = 0; i < 5; i++) {
NSLog(@"download2-%zd-%@",i,[NSThread currentThread]);
}
});
/* 2. 柵欄函數(shù) */
dispatch_barrier_sync(concurrentQueue, ^{
NSLog(@"---------------------%@------------------------",[NSThread currentThread]);
});
NSLog(@"加載那么多,喘口氣!!!");
/* 3. 異步函數(shù) */
dispatch_async(concurrentQueue, ^{
for (NSUInteger i = 0; i < 5; i++) {
NSLog(@"日常處理3-%zd-%@",i,[NSThread currentThread]);
}
});
NSLog(@"**********起來(lái)干!!");
dispatch_async(concurrentQueue, ^{
for (NSUInteger i = 0; i < 5; i++) {
NSLog(@"日常處理4-%zd-%@",i,[NSThread currentThread]);
}
});
}
調(diào)度組:
用這個(gè)也可以控制任務(wù)調(diào)度順序。用法如下:
- (void)groupDemo {
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"第一個(gè)走完了");
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"第二個(gè)走完了");
dispatch_group_leave(group);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"所有任務(wù)完成,可以更新UI");
});
}
注意:
1.dispatch_group_enter與 dispatch_group_leave需要成對(duì)出現(xiàn)。
2.dispatch_group_enter 多于 dispatch_group_leave 不會(huì)調(diào)用通知
3.dispatch_group_enter 少于 dispatch_group_leave 會(huì)奔潰
4.所有的dispatch_group_enter都要在dispatch_group_notify之前執(zhí)行。