GCD中有兩種queue,分別為下面兩種
生成Dispatch Queue的方法
一:dispatch_queue_create
- 生成Serial Dispatch Queue
- 生成Concurrent Dispatch Queue
生成的Dispatch Queue必須由程序員負(fù)責(zé)釋放,這是因?yàn)镈ispatch Queue並沒(méi)有像 Block那樣具有作為<OC對(duì)象>來(lái)處理的技術(shù),代碼如下
- 在通過(guò)函數(shù)或方法獲取Dispatch Queue 以及其他名稱中含有 create 的API生成的對(duì)象時(shí),有必要通過(guò) dispatch_retain函數(shù)持有,並在不需要時(shí) dispatch_release釋放
二:Main Dispatch Queue/Global Dispatch Queue
//Main Dispatch Queue 的獲取方法
dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
//Global Dispatch Queue(高優(yōu)先級(jí))的獲取方法
dispatch_queue_t golbalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
//Global Dispatch Queue(默認(rèn)優(yōu)先級(jí))
dispatch_queue_t golbalDispatchQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//Global Dispatch Queue(低優(yōu)先級(jí))
dispatch_queue_t golbalDispatchQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
//Global Dispatch Queue(後臺(tái)優(yōu)先級(jí))
dispatch_queue_t golbalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
- 對(duì)於Main Dispatch Queue和Golbal Dispatch Queue執(zhí)行dispatch_retain 和 dispatch_release函數(shù)不會(huì)引起任何變化,也不會(huì)有任何問(wèn)題
-
dispatch_set_target_queue
dispatch_queue_create生成的queue都與默認(rèn)優(yōu)先級(jí)的global dispatch queue相同執(zhí)行優(yōu)先級(jí)的線程,如需將其變?yōu)獒崤_(tái)優(yōu)先級(jí)可參考下面代碼
dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.atsmart.gcd.MySerialDispatchQueue", NULL);
dispatch_queue_t golbalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_set_target_queue(mySerialDispatchQueue, golbalDispatchQueueBackground);
如果在多個(gè)serial dispatch queue 中用 dispatch_set_target_queue函數(shù)指定某一個(gè)serial dispatch queue,那麼原本可以並行執(zhí)行的多個(gè)serial dispatch queue,在目標(biāo)serial dispatch queue上也只能執(zhí)行一個(gè)處理,示意圖如下(如果有需求需要將多個(gè)queue按順序執(zhí)行可用此方法)
-
dispatch_afer
iOS多線程中performSelector: 和dispatch_time的不同
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC);
dispatch_after(time, dispatch_get_main_queue(), ^{
NSLog(@"");
});
上面代碼不代表在3秒後就執(zhí)行,而是3秒後加入到主隊(duì)列中
-
dispatch_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(@"blk0");});
dispatch_group_async(group, queue, ^{NSLog(@"blk1");});
dispatch_group_async(group, queue, ^{NSLog(@"blk2");});
dispatch_group_async(group, queue, ^{NSLog(@"blk3");});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"done");
});
queue是並行隊(duì)列,所以blk0,blk1,blk2,blk3不能保證順序執(zhí)行,但是可以保證done是最後打印出來(lái)
也可以僅僅等待全部任務(wù)結(jié)束
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
-
dispatch_group_wait的另一種用法,隔多少時(shí)間判斷裏面任務(wù)是否執(zhí)行完畢
image.png -
dispatch_barrier_async
對(duì)於數(shù)據(jù)庫(kù),我們?cè)趯懭氲臅r(shí)候要保證不能有多個(gè)動(dòng)作同時(shí)進(jìn)行,因?yàn)闀?huì)
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(@"blk0_for_reading");});
dispatch_group_async(group, queue, ^{NSLog(@"blk1_for_reading");});
dispatch_barrier_async(queue, ^{
NSLog(@"writing");
});
dispatch_group_async(group, queue, ^{NSLog(@"blk2_for_reading");});
dispatch_group_async(group, queue, ^{NSLog(@"blk3_for_readinglk3");});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"done");
});
dispatch_sync
-
容易發(fā)生死鎖的幾個(gè)例子:
1,主線程正在執(zhí)行代碼,你又等待主線程執(zhí)行完畢,所以死鎖
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
NSLog(@"hello??");
});
dispatch_queue_t queue = dispatch_queue_create("xxx", NULL);
dispatch_async(queue, ^{
dispatch_sync(queue, ^{
NSLog(@"hello?");
});
});
- dispatch_apply
指定次數(shù)將Block加入指定Queue中,並等待全部處理執(zhí)行完畢,示例代碼如下
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
dispatch_apply([array count], queue, ^(size_t index) {
NSLog(@"%zu:%@",index,[array objectAtIndex:index]);
});
//dispatch_apply函數(shù)中處理全部執(zhí)行完畢
dispatch_async(dispatch_get_main_queue(), ^{
//可執(zhí)行用戶更新操作等
NSLog(@"done");
});
});
dispatch_suspend/dispatch_resume
可以掛起和重新恢復(fù)執(zhí)行queue
- dispatch semaphore
下面代碼會(huì)因?yàn)橥瑫r(shí)很多線程操作數(shù)組導(dǎo)致系統(tǒng)奔潰
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSMutableArray *array = [[NSMutableArray alloc]init];
for (int i = 0; i<1000; ++i) {
dispatch_async(queue, ^{
[array addObject:[NSNumber numberWithInt:i]];
});
}
改進(jìn)如下
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);//保證可訪問(wèn)array的線程只能有一個(gè)
NSMutableArray *array = [[NSMutableArray alloc]init];
for (int i = 0; i<100000; ++i) {
dispatch_async(queue, ^{
//等待semaphore,直到semaphore值大於或者等於1
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//第一次我們?cè)O(shè)置為1所以可以直接下來(lái)執(zhí)行,然後會(huì)semaphore減1,現(xiàn)在變?yōu)?
[array addObject:[NSNumber numberWithInt:i]];
//執(zhí)行完後還是0,需要進(jìn)行加1操作,semaphore
dispatch_semaphore_signal(semaphore);
//semaphore為1後,才可以進(jìn)行下一次循環(huán)
});
}
- dispath_once
一般用來(lái)初始化操作,保證在多線程環(huán)境下也能安全
Dispatch I/O
`