兩個特殊隊列:
dispatch_get_main_queue()
主隊列,串行隊列囤踩。
dispatch_get_global_queue(0, 0)
全局并發(fā)隊列限匣。這個隊列是系統維護的,會被用來處理很多系統級事件毡熏。
最簡單的block:
dispatch_block_t
這是個無參無返回值的block。
關于同步異步函數:
dispatch_sync
同步函數沒有開啟線程的能力倦蚪。所有的代碼都會在當前線程立即執(zhí)行希坚。
dispatch_async
異步函數有開啟線程的能力。
關于串行并行隊列:
dispatch_queue_create(0,0)
DISPATCH_CURRENT_QUEUE_LABEL
串行隊列遵循FIFO原則审丘,先進先出吏够。
DISPATCH_QUEUE_CONCURRENT
并行隊列,之間不會相互影響會各自執(zhí)行滩报。執(zhí)行順序與加入隊列順序有關锅知。
排列組合之后,就有了這么一套機制脓钾,如下圖:
知識點較多的主要是同步函數串行隊列售睹。產生堵塞的原因本質上還是任務執(zhí)行順序的問題。如下經典代碼就會產生堵塞(死鎖):
// 同步隊列
dispatch_queue_t queue = dispatch_queue_create("xxx", DISPATCH_QUEUE_SERIAL);
NSLog(@"1");
// 異步函數
dispatch_async(queue, ^{
NSLog(@"2");
// 同步
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
分析圖如下
本質上可训,異步函數里的代碼是加入隊列后昌妹,按順序執(zhí)行的。所以會執(zhí)行2->同步->4
握截。
但是飞崖,同步函數的性質又會讓代碼立即執(zhí)行。所以在執(zhí)行同步函數的時候谨胞,會要求立即執(zhí)行log3
固歪。
但是log3
這個任務因為串行隊列順序的原因,必須等到log4執(zhí)行完畢之后才會執(zhí)行胯努。
此時發(fā)生了log4
與log3
相互等待的情況牢裳,而產生了堵塞。
這只是同步串行會出現問題的一種方式叶沛。單純的在主線程中使用同步串行蒲讯,是沒有問題,而且借助其一定會按順序執(zhí)行的特性灰署。還能達到某些鎖的功能:如經典的購票問題:
- (void)saleTickes {
self.tickets = 20;
_queue = dispatch_queue_create("xxx", DISPATCH_QUEUE_SERIAL);
while (self.tickets > 0) {
// 使用串行隊列判帮,同步任務賣票
dispatch_sync(_queue, ^{
// 檢查票數
if (self.tickets > 0) {
self.tickets--;
}
});
}
}
代碼很簡單,不需要解釋氓侧。這個demo只是說明同步串行的效果脊另。其實這段代碼意義不大,因為實現購票必定要在異步并發(fā)隊列里才會更好的達到效果约巷。如下:
- (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, ^{
// 檢查票數
if (self.tickets > 0) {
self.tickets--;
NSLog(@"還剩 %zd %@", self.tickets, [NSThread currentThread]);
} else {
NSLog(@"沒有票了");
}
[lock unlock];
});
}
}
柵欄函數:
柵欄函數的用法偎痛,多用于控制并發(fā)隊列
的執(zhí)行時機,并且只用于控制唯一一個并發(fā)隊列(控制串行隊列沒有意義)独郎。其中的barrier
單詞很好的說明了他的作用踩麦。就是個擋路的:在我之前的任務都要被我擋住枚赡,等我執(zhí)行完畢之后,之后的任務才會執(zhí)行谓谦。
dispatch_barrier_sync
同步柵欄函數:不僅僅會阻擋 并發(fā)隊列的任務贫橙,還會阻擋 當前線程的任務 。直至該函數 之前的并發(fā)隊列任務 執(zhí)行完畢后反粥,才會繼續(xù)執(zhí)行 當前線程的任務 與 后面的并發(fā)任務 卢肃。
dispatch_barrier_async
異步柵欄函數:只阻擋 并發(fā)隊列的任務 。不會阻擋 當前線程的任務 才顿。所以 當前線程的任務 莫湘,都會比 所有的并發(fā)隊列的任務 先執(zhí)行。
demo如下:就不解釋了
- (void)demo2{
dispatch_queue_t concurrentQueue = dispatch_queue_create("cooci", DISPATCH_QUEUE_CONCURRENT);
/* 1.異步函數 */
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. 柵欄函數 */
dispatch_barrier_sync(concurrentQueue, ^{
NSLog(@"---------------------%@------------------------",[NSThread currentThread]);
});
NSLog(@"加載那么多,喘口氣!!!");
/* 3. 異步函數 */
dispatch_async(concurrentQueue, ^{
for (NSUInteger i = 0; i < 5; i++) {
NSLog(@"日常處理3-%zd-%@",i,[NSThread currentThread]);
}
});
NSLog(@"**********起來干!!");
dispatch_async(concurrentQueue, ^{
for (NSUInteger i = 0; i < 5; i++) {
NSLog(@"日常處理4-%zd-%@",i,[NSThread currentThread]);
}
});
}
調度組:
用這個也可以控制任務調度順序郑气。用法如下:
- (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(@"第一個走完了");
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"第二個走完了");
dispatch_group_leave(group);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"所有任務完成,可以更新UI");
});
}
注意:
1.dispatch_group_enter
與 dispatch_group_leave
需要成對出現幅垮。
2.dispatch_group_enter
多于 dispatch_group_leave
不會調用通知
3.dispatch_group_enter
少于 dispatch_group_leave
會奔潰
4.所有的dispatch_group_enter
都要在dispatch_group_notify
之前執(zhí)行。