首先看一段代碼
- (void)syncTestWithQueue:(dispatch_queue_t)queue {
NSLog(@"sync 1");
dispatch_sync(queue, ^{
NSLog(@"start 1");
sleep(1);
NSLog(@"end 1");
});
NSLog(@"sync 2");
dispatch_sync(queue, ^{
NSLog(@"start 2");
sleep(1);
NSLog(@"end 2");
});
NSLog(@"sync 3");
dispatch_sync(queue, ^{
NSLog(@"start 3");
sleep(1);
NSLog(@"end 3");
});
NSLog(@"sync 4");
dispatch_barrier_sync(queue, ^{
NSLog(@"sync barrier start 1");
sleep(1);
NSLog(@"sync barrier end 1");
});
NSLog(@"sync 5");
dispatch_sync(queue, ^{
NSLog(@"start 4");
sleep(1);
NSLog(@"end 4");
});
NSLog(@"sync 6");
}
- (void)asyncTestWithQueue:(dispatch_queue_t)queue {
NSLog(@"async 1");
dispatch_async(queue, ^{
NSLog(@"start 1");
sleep(1);
NSLog(@"end 1");
});
NSLog(@"async 2");
dispatch_async(queue, ^{
NSLog(@"start 2");
sleep(1);
NSLog(@"end 2");
});
NSLog(@"async 3");
dispatch_async(queue, ^{
NSLog(@"start 3");
sleep(1);
NSLog(@"end 3");
});
NSLog(@"async 4");
dispatch_barrier_async(queue, ^{
NSLog(@"async barrier start 1");
sleep(1);
NSLog(@"async barrier end 1");
});
NSLog(@"async 5");
dispatch_async(queue, ^{
NSLog(@"start 4");
sleep(1);
NSLog(@"end 4");
});
NSLog(@"async 6");
}
用并行隊(duì)列來測試一下窒朋。
1.自定義并行隊(duì)列
dispatch_queue_t concurrentQueue=dispatch_queue_create("并行隊(duì)列", DISPATCH_QUEUE_CONCURRENT);
[self syncTestWithQueue:concurrentQueue];
[self asyncTestWithQueue:concurrentQueue];
打印結(jié)果分別為
在同步執(zhí)行時寓辱,并行隊(duì)列跟串行隊(duì)列一樣,按任務(wù)順序一個接一個進(jìn)行蚊荣。而在異步的時候初狰,會出現(xiàn)end 2
比end 1
提前打印的情況,雖然并行隊(duì)列的執(zhí)行順序也是按任務(wù)添加順序來的互例,但是完成順序就不一定了奢入。
其中,用dispatch_barrier_sync
時媳叨,sync 5
的打印在sync barrier start 1
后面腥光,這時候跟普通的sync
一樣关顷,下面的代碼要等待sync
執(zhí)行完后才能執(zhí)行。而用dispatch_barrier_async
時武福,async 5
打印在async barrier start 1
之前议双,這就說明start 4
其實(shí)已經(jīng)被添加進(jìn)當(dāng)前的queue
了,只是要等待barrier執(zhí)行完畢才能執(zhí)行艘儒。
2.全局并發(fā)隊(duì)列(dispatch_get_global_queue)
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
[self syncTestWithQueue:globalQueue];
[self asyncTestWithQueue:globalQueue];
同步時打印結(jié)果跟上面的一樣聋伦,異步時打印結(jié)果如下夫偶。
可以看到當(dāng)queue
是全局隊(duì)列的時候界睁,這時候的dispatch_barrier_async
,并沒有阻塞當(dāng)前的queue
兵拢,就像普通的async
一樣在執(zhí)行翻斟,這是為什么呢?
在官方文檔里说铃,對于
dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
的queue
访惜,有說明
dispatch_barrier
只能在你自己創(chuàng)建的并發(fā)隊(duì)列下使用(當(dāng)使用的是dispatch_barrier_sync
時,文檔最后面就是dispatch_sync
腻扇,其余部分都是一樣的债热,就不貼兩張圖了)。這個又是為啥呢幼苛?
從官方文檔和這張關(guān)系圖可以看出:
-
main_queue
和global_queue
可以說是所有自定義隊(duì)列的“父隊(duì)列”
窒篱,由系統(tǒng)管理,并且不受retain
和release
的影響舶沿。 - 不管是
serial_queue
墙杯,還是concurrent_queue
,最后都會回到main_queue
或者是global_queue
括荡,然后歸于主線程或者是GCD的線程池進(jìn)行管理高镐。
在上面queue
為自定義并發(fā)隊(duì)列時,dispatch_barrier_async
里面的任務(wù)會等到當(dāng)前queue
前面的任務(wù)都執(zhí)行完了才能執(zhí)行畸冲,并且在barrier
之后添加的任務(wù)嫉髓,要等到barrier
執(zhí)行完才能進(jìn)行。
如果barrier
能夠影響到global_queue
邑闲,那么barrier
就會阻塞global_queue
岩喷,而對于global_queue
,它是當(dāng)前app的核心隊(duì)列监憎,并不僅僅只有“你”在用纱意,一旦阻塞,后果是災(zāi)難性的鲸阔。所以蘋果就對它進(jìn)行了特殊處理偷霉,對于global_queue
和main_queue
迄委,我們都只有使用權(quán),沒有操作權(quán)类少。