iOS開發(fā)之多線程編程總結(jié)(二)

背景

擔(dān)心了兩周的我終于輪到去醫(yī)院做胃鏡檢查了!去的時(shí)候我都想好了最壞的可能(胃癌)巍举,之前在網(wǎng)上查的癥狀都很相似窜锯。最后檢查結(jié)果出來終于安心了蚌成,診斷結(jié)果:慢性非萎縮性胃炎(胃竇為主)

我是一個(gè)心里素質(zhì)不過關(guān)的人,所以說對(duì)待問題的時(shí)候可能會(huì)有一種悲觀的想法晌砾。朋友說我本來可能沒病都被自己嚇出病了坎拐,這是一個(gè)心態(tài)問題。

你們可能問我做胃鏡什么感覺养匈?我只能告訴你一個(gè)字:真爽哼勇,具體只能自己去感受。

自己眼中的自己.jpg

保持樂觀的心態(tài)

看完下面的笑話就要開始我們的裝逼之旅了_

  1. 一個(gè)大學(xué)生去公司實(shí)習(xí)呕乎,老板讓他先從掃地開始积担。大學(xué)生:“我可是大學(xué)生哎……”老板:“哦,對(duì)了楣嘁,我差點(diǎn)忘了你是大學(xué)生磅轻,來來來珍逸,我教你怎么掃地”
  1. 一天,老師讓同學(xué)們寫作文聋溜,題目是 《我的理想》谆膳。
    小明在作文里寫道:我長大了要去搶銀行,然后把錢分給窮苦老百姓撮躁。
    第二天老師改完了漱病,寫給小明的評(píng)語是這樣的:很不錯(cuò)的理想,分錢的時(shí)候不要忘了老師把曼,但你要注意你的同桌杨帽,他說他長大了要去當(dāng)警察。

GCD基本介紹

  • GCD(Grand Central Dispatch)iOS 4.0開始引入的新多線程編程功能,
  • GCD(Grand Central Dispatch)是異步執(zhí)行任務(wù)的技術(shù)之一嗤军。一般將應(yīng)用程序中記述的線程管理用的代碼在系統(tǒng)級(jí)中實(shí)現(xiàn)注盈。開發(fā)者只需要定義想執(zhí)行的任務(wù)并追加到適當(dāng)?shù)腄ispatch Queue中,GCD就能生成必要的線程并計(jì)劃執(zhí)行任務(wù)叙赚。
  • GCD(Grand Central Dispatch)是基于C語言開發(fā)的一套多線程開發(fā)機(jī)制老客,是完全面向過程的。

GCD基本概念

這就需要上一篇博客里的基本知識(shí)了(不清楚去看下)iOS開發(fā)之多線程編程總結(jié)(一)

任務(wù)和隊(duì)列

  • 任務(wù):就是執(zhí)行操作的意思震叮,換句話說就是你在線程中執(zhí)行的那段代碼胧砰。在GCD中是放在block中的。執(zhí)行任務(wù)有兩種方式:同步執(zhí)行異步執(zhí)行苇瓣。兩者的主要區(qū)別是:是否具備開啟新線程的能力勤揩。

    1. 同步執(zhí)行(sync):只能在當(dāng)前線程中執(zhí)行任務(wù)弥激,不具備開啟新線程的能力
    • 必須等待當(dāng)前語句執(zhí)行完畢,才會(huì)執(zhí)行下一條語句
    • 不會(huì)開啟線程
    • 在當(dāng)前主線程執(zhí)行 block 的任務(wù)
    • dispatch_sync(queue, block);
    1. ** 異步執(zhí)行(async)**:可以在新的線程中執(zhí)行任務(wù),具備開啟新線程的能力
    • 不用等待當(dāng)前語句執(zhí)行完畢绣的,就可以執(zhí)行下一條語句
    • 會(huì)開啟線程執(zhí)行 block 的任務(wù)
    • 異步是多線程的代名詞
    • dispatch_async(queue, block);
  • 隊(duì)列:這里的隊(duì)列指任務(wù)隊(duì)列真仲,即用來存放任務(wù)的隊(duì)列益咬。隊(duì)列是一種特殊的線性表奕短,采用FIFO(先進(jìn)先出)的原則,即新任務(wù)總是被插入到隊(duì)列的末尾损话,而讀取任務(wù)的時(shí)候總是從隊(duì)列的頭部開始讀取侦啸。每讀取一個(gè)任務(wù),則從隊(duì)列中釋放一個(gè)任務(wù)丧枪。在GCD中有四種隊(duì)列:串行隊(duì)列光涂、并發(fā)隊(duì)列主隊(duì)列拧烦、全局隊(duì)列忘闻。

    1. 串行隊(duì)列(Serial Dispatch Queue):讓任務(wù)一個(gè)接著一個(gè)地執(zhí)行(一個(gè)任務(wù)執(zhí)行完畢后,再執(zhí)行下一個(gè)任務(wù))

      • 一次只能"調(diào)度"一個(gè)任務(wù)
      • dispatch_queue_create("queue", NULL);
        或者dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    2. 并發(fā)隊(duì)列(Concurrent Dispatch Queue):可以讓多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行(自動(dòng)開啟多個(gè)線程同時(shí)執(zhí)行任務(wù))恋博,

      • 一次可以"調(diào)度"多個(gè)任務(wù)
      • 并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效
      • dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    3. 主隊(duì)列

      • 專門用來在主線程上調(diào)度任務(wù)的隊(duì)列
      • 不會(huì)開啟線程
      • 在主線程空閑時(shí)才會(huì)調(diào)度隊(duì)列中的任務(wù)在主線程執(zhí)行
      • dispatch_get_main_queue();
    4. 全局隊(duì)列

      • 執(zhí)行過程和并發(fā)隊(duì)列一致齐佳,參考并發(fā)隊(duì)列
      • dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

小結(jié): 在以后的使用中私恬,記住下面的就可以了!

  1. 開不開線程由執(zhí)行任務(wù)的函數(shù)決定
  • 異步開炼吴,異步是多線程的代名詞
  • 同步不開
  1. 開幾條線程由隊(duì)列決定
  • 串行隊(duì)列開一條線程(GCD會(huì)開一條本鸣,NSOperation Queue最大并發(fā)數(shù)為1時(shí)也可能開多條)
  • 并發(fā)隊(duì)列開多條線程,具體能開的線程數(shù)量由底層線程池決定

GCD的使用

今天我們學(xué)習(xí)下面圖片的相關(guān)知識(shí)點(diǎn)硅蹦,Demo下載鏈接會(huì)在文章最后給出來


GCD知識(shí)點(diǎn).png

簡單來看一段代碼:異步下載圖片

#pragma mark - 1.異步下載圖片
- (IBAction)downLoadAction:(UIButton *)sender {
    self.imageView.image = nil;
    //獲取全局隊(duì)列
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        //異步下載圖片
        NSURL *url=[NSURL URLWithString:@"https://p1.bpimg.com/524586/475bc82ff016054ds.jpg"];
        //將資源轉(zhuǎn)換為二進(jìn)制
        NSData *data=[NSData dataWithContentsOfURL:url];
        //將二進(jìn)制轉(zhuǎn)化為圖片
        UIImage *image=[UIImage imageWithData:data];
        
        //獲取主隊(duì)列,更新UI
        dispatch_async(dispatch_get_main_queue(), ^{
            //給圖片控件賦值
            self.imageView.image=image;
        });
    });
}

NSThread對(duì)比可以發(fā)現(xiàn)

  • 所有的代碼寫在一起的荣德,讓代碼更加簡單,易于閱讀和維護(hù)
  • NSThread 通過 @selector 指定要執(zhí)行的方法童芹,代碼分散
  • GCD 通過 block 指定要執(zhí)行的代碼涮瞻,代碼集中
  • 使用 GCD 不需要管理線程的創(chuàng)建/銷毀/復(fù)用的過程!程序員不用關(guān)心線程的生命周期
  • 如果要開多個(gè)線程 NSThread 必須實(shí)例化多個(gè)線程對(duì)象或者使用分類方法
  • NSThread 靠 NSObject 的分類方法實(shí)現(xiàn)的線程間通訊假褪,GCD 靠 block
  • dispatch_async(queue, block);就是異步執(zhí)行一個(gè)隊(duì)列里面的任務(wù)block署咽。每個(gè)block之間是異步執(zhí)行的,但是block里面的代碼是順序執(zhí)行的嗜价!
  • dispatch_sync(queue, block);就是同步執(zhí)行一個(gè)隊(duì)列里面的任務(wù)block

1. 串行隊(duì)列(Serial Dispatch Queue)

串行隊(duì)列的創(chuàng)建:
 dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
 dispatch_queue_t queue = dispatch_queue_create("queue", NULL);
串行隊(duì)列同步和異步執(zhí)行Demo:
 #pragma mark - 串行隊(duì)列同步和串行隊(duì)列異步
 //串行隊(duì)列同步
 - (void)serialQueueSyncMethod{
     //創(chuàng)建隊(duì)列
     dispatch_queue_t queue = dispatch_queue_create("serialQueueSyncMethod", DISPATCH_QUEUE_SERIAL);
     //執(zhí)行任務(wù)
     for (int i = 0; i < 6; i++) {
         NSLog(@"mainThread--->%d",i);
         dispatch_sync(queue, ^{
             NSLog(@"Current Thread=%@---->%d-----",[NSThread currentThread],i);
         });
     }
     NSLog(@"串行隊(duì)列同步end");
  }

 //串行隊(duì)列異步
  - (void)serialQueueAsyncMethod{
     dispatch_queue_t queue = dispatch_queue_create("serialQueueAsyncMethod", DISPATCH_QUEUE_SERIAL);
     for (int i = 0; i < 6; i++) {
         NSLog(@"mainThread--->%d",i);
         dispatch_async(queue, ^{
             NSLog(@"Current Thread=%@---->%d-----",[NSThread currentThread],i);
         });
     }
     NSLog(@"串行隊(duì)列異步end");
  }   
串行隊(duì)列 同步執(zhí)行結(jié)果:
2016-11-03 17:16:35.794 ThreadDemo[27088:5268309] mainThread--->0
2016-11-03 17:16:35.795 ThreadDemo[27088:5268309] Current Thread=<NSThread: 0x60800007ae40>{number = 1, name = main}---->0-----
2016-11-03 17:16:35.795 ThreadDemo[27088:5268309] mainThread--->1
2016-11-03 17:16:35.795 ThreadDemo[27088:5268309] Current Thread=<NSThread: 0x60800007ae40>{number = 1, name = main}---->1-----
2016-11-03 17:16:35.795 ThreadDemo[27088:5268309] mainThread--->2
2016-11-03 17:16:35.795 ThreadDemo[27088:5268309] Current Thread=<NSThread: 0x60800007ae40>{number = 1, name = main}---->2-----
2016-11-03 17:16:35.795 ThreadDemo[27088:5268309] mainThread--->3
2016-11-03 17:16:35.796 ThreadDemo[27088:5268309] Current Thread=<NSThread: 0x60800007ae40>{number = 1, name = main}---->3-----
2016-11-03 17:16:35.796 ThreadDemo[27088:5268309] mainThread--->4
2016-11-03 17:16:35.796 ThreadDemo[27088:5268309] Current Thread=<NSThread: 0x60800007ae40>{number = 1, name = main}---->4-----
2016-11-03 17:16:35.796 ThreadDemo[27088:5268309] mainThread--->5
2016-11-03 17:16:35.796 ThreadDemo[27088:5268309] Current Thread=<NSThread: 0x60800007ae40>{number = 1, name = main}---->5-----
2016-11-03 17:16:35.796 ThreadDemo[27088:5268309] 串行隊(duì)列同步end
串行隊(duì)列 異步執(zhí)行結(jié)果:
2016-11-03 17:22:25.074 ThreadDemo[27122:5273206] mainThread--->0
2016-11-03 17:22:25.074 ThreadDemo[27122:5273206] mainThread--->1
2016-11-03 17:22:25.074 ThreadDemo[27122:5273252] Current Thread=<NSThread: 0x60800007f380>{number = 5, name = (null)}---->0-----
2016-11-03 17:22:25.074 ThreadDemo[27122:5273206] mainThread--->2
2016-11-03 17:22:25.074 ThreadDemo[27122:5273252] Current Thread=<NSThread: 0x60800007f380>{number = 5, name = (null)}---->1-----
2016-11-03 17:22:25.074 ThreadDemo[27122:5273206] mainThread--->3
2016-11-03 17:22:25.075 ThreadDemo[27122:5273252] Current Thread=<NSThread: 0x60800007f380>{number = 5, name = (null)}---->2-----
2016-11-03 17:22:25.075 ThreadDemo[27122:5273206] mainThread--->4
2016-11-03 17:22:25.075 ThreadDemo[27122:5273252] Current Thread=<NSThread: 0x60800007f380>{number = 5, name = (null)}---->3-----
2016-11-03 17:22:25.075 ThreadDemo[27122:5273206] mainThread--->5
2016-11-03 17:22:25.075 ThreadDemo[27122:5273252] Current Thread=<NSThread: 0x60800007f380>{number = 5, name = (null)}---->4-----
2016-11-03 17:22:25.075 ThreadDemo[27122:5273206] 串行隊(duì)列異步end
2016-11-03 17:22:25.075 ThreadDemo[27122:5273252] Current Thread=<NSThread: 0x60800007f380>{number = 5, name = (null)}---->5-----
小結(jié):
  • 從串行隊(duì)列同步執(zhí)行結(jié)果看出打印是交替執(zhí)行的艇抠!從打印中看到number=1,說明線程block任務(wù)是在主線程中執(zhí)行的久锥。因?yàn)?strong>同步是不會(huì)開辟線程的,所有當(dāng)前只有一個(gè)主線程MainThread异剥。也就是說串行隊(duì)列同步執(zhí)行不會(huì)開辟線程瑟由,所有block任務(wù)之間是同步執(zhí)行的
  • 從串行隊(duì)列異步執(zhí)行結(jié)果看出打印并不是交替執(zhí)行的!從打印中看到number=5冤寿,說明線程block的任務(wù)是在一個(gè)全新的線程中執(zhí)行的歹苦。因?yàn)?strong>異步是會(huì)開辟線程的,所有當(dāng)前有主線程MainThread和子線程number=5督怜。也就是說串行隊(duì)列異步執(zhí)行會(huì)僅會(huì)開辟一個(gè)新的線程殴瘦,所有block任務(wù)之間是同步執(zhí)行的
  • 以先進(jìn)先出的方式,順序調(diào)度隊(duì)列中的任務(wù)執(zhí)行
  • 無論隊(duì)列中指定的任務(wù)函數(shù)是同步還是異步,都會(huì)等待前一個(gè)任務(wù)執(zhí)行完畢以后,再調(diào)度后面的任務(wù)

2. 并發(fā)隊(duì)列(Concurrent Dispatch Queue)

并發(fā)隊(duì)列創(chuàng)建
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
并發(fā)隊(duì)列同步和異步執(zhí)行Demo
 #pragma mark - 并行隊(duì)列同步和并行隊(duì)列異步
 //并行隊(duì)列同步
 - (void)concurrentQueueSyncMethod{
     dispatch_queue_t queue = dispatch_queue_create("concurrentQueueSyncMethod", DISPATCH_QUEUE_CONCURRENT);
    
     for (int i = 0; i < 6; i++) {
         dispatch_sync(queue, ^{
             NSLog(@"Current Thread=%@---->%d-----",[NSThread currentThread],i);
         });
     }
     NSLog(@"并行隊(duì)列同步end");
  }

 //并行隊(duì)列異步
- (void)concurrentQueueAsyncMethod{
     dispatch_queue_t queue = dispatch_queue_create("concurrentQueueAsyncMethod", DISPATCH_QUEUE_CONCURRENT);

     for (int i = 0; i < 6; i++) {
         dispatch_async(queue, ^{
             NSLog(@"Current Thread=%@---->%d-----",[NSThread currentThread],i);
         });
     }
    
     NSLog(@"并行隊(duì)列異步end");
  }      
并發(fā) 隊(duì)列同步執(zhí)行結(jié)果:
2016-11-03 17:49:33.850 ThreadDemo[27176:5290096] Current Thread=<NSThread: 0x60000007bf00>{number = 1, name = main}---->0-----
2016-11-03 17:49:33.851 ThreadDemo[27176:5290096] Current Thread=<NSThread: 0x60000007bf00>{number = 1, name = main}---->1-----
2016-11-03 17:49:33.851 ThreadDemo[27176:5290096] Current Thread=<NSThread: 0x60000007bf00>{number = 1, name = main}---->2-----
2016-11-03 17:49:33.851 ThreadDemo[27176:5290096] Current Thread=<NSThread: 0x60000007bf00>{number = 1, name = main}---->3-----
2016-11-03 17:49:33.851 ThreadDemo[27176:5290096] Current Thread=<NSThread: 0x60000007bf00>{number = 1, name = main}---->4-----
2016-11-03 17:49:33.851 ThreadDemo[27176:5290096] Current Thread=<NSThread: 0x60000007bf00>{number = 1, name = main}---->5-----
2016-11-03 17:49:33.851 ThreadDemo[27176:5290096] 并行隊(duì)列同步end
并發(fā)隊(duì)列 異步執(zhí)行結(jié)果:
2016-11-03 18:33:32.794 ThreadDemo[27283:5311953] 并行隊(duì)列異步end
2016-11-03 18:33:32.794 ThreadDemo[27283:5312009] Current Thread=<NSThread: 0x60800026b8c0>{number = 3, name = (null)}---->0-----
2016-11-03 18:33:32.794 ThreadDemo[27283:5312006] Current Thread=<NSThread: 0x600000269180>{number = 4, name = (null)}---->1-----
2016-11-03 18:33:32.794 ThreadDemo[27283:5312003] Current Thread=<NSThread: 0x600000268f80>{number = 6, name = (null)}---->3-----
2016-11-03 18:33:32.794 ThreadDemo[27283:5312174] Current Thread=<NSThread: 0x60800026b740>{number = 8, name = (null)}---->5-----
2016-11-03 18:33:32.794 ThreadDemo[27283:5312004] Current Thread=<NSThread: 0x60800026b7c0>{number = 5, name = (null)}---->2-----
2016-11-03 18:33:32.794 ThreadDemo[27283:5312173] Current Thread=<NSThread: 0x60800026b800>{number = 7, name = (null)}---->4-----
小結(jié):
  • 并發(fā)隊(duì)列同步執(zhí)行和串行隊(duì)列同步執(zhí)行一樣,都不會(huì)開辟新線程号杠,block任務(wù)之間是同步執(zhí)行的蚪腋!
  • 并發(fā)隊(duì)列異步執(zhí)行結(jié)果中看到開辟了多個(gè)線程,并且執(zhí)行順序也不是順序執(zhí)行姨蟋。因?yàn)?strong>異步開多線程的代名詞屉凯,并發(fā)是開多條線程的代名詞
  • 有多個(gè)線程,操作進(jìn)來之后它會(huì)將這些隊(duì)列安排在可用的處理器上眼溶,同時(shí)保證先進(jìn)來的任務(wù)優(yōu)先處理悠砚。
  • 以先進(jìn)先出的方式,并發(fā)調(diào)度隊(duì)列中的任務(wù)執(zhí)行
  • 如果當(dāng)前調(diào)度的任務(wù)是同步執(zhí)行的堂飞,會(huì)等待任務(wù)執(zhí)行完成后灌旧,再調(diào)度后續(xù)的任務(wù)
  • 如果當(dāng)前調(diào)度的任務(wù)是異步執(zhí)行的绑咱,同時(shí)底層線程池有可用的線程資源,會(huì)再新的線程調(diào)度后續(xù)任務(wù)的執(zhí)行

3. 全局隊(duì)列(Global Dispatch Queue)

全局隊(duì)列基本知識(shí)
  • dispatch_get_global_queue函數(shù)來獲取
  • 全局隊(duì)列是所有應(yīng)用程序都能夠使用的并發(fā)隊(duì)列(Concurrent Dispatch Queue)枢泰,沒必要通過dispatch_queue_create函數(shù)逐個(gè)生成并發(fā)隊(duì)列羡玛,只需要獲取Global Dispatch Queue即可
  • 是系統(tǒng)為了方便程序員開發(fā)提供的,其工作表現(xiàn)與并發(fā)隊(duì)列一致宗苍、其工作表現(xiàn)與并發(fā)隊(duì)列一致稼稿、其工作表現(xiàn)與并發(fā)隊(duì)列一致
  • Global Dispatch Queue有4個(gè)優(yōu)先級(jí),分別是高優(yōu)先級(jí)讳窟、默認(rèn)優(yōu)先級(jí)让歼、低優(yōu)先級(jí)、后臺(tái)優(yōu)先級(jí)丽啡!因?yàn)閄NU內(nèi)核用于Global Dispatch Queue的線程并不能保證實(shí)時(shí)性谋右,因此執(zhí)行優(yōu)先級(jí)知識(shí)大概的判斷和區(qū)分。
  #define DISPATCH_QUEUE_PRIORITY_HIGH 2
  #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
  #define DISPATCH_QUEUE_PRIORITY_LOW (-2)
  #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
全局隊(duì)列同步和異步執(zhí)行Demo
 #pragma mark -全局隊(duì)列同步和全局隊(duì)列異步(工作表現(xiàn)與并發(fā)隊(duì)列一致)
 //全局隊(duì)列同步
 - (void)globalSyncMethod{
     //獲取全局隊(duì)列
       dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     //執(zhí)行任務(wù)
     for (int i = 0; i < 10; ++i) {
         dispatch_sync(queue, ^{
             NSLog(@"global_queue_sync%@---->%d----",[NSThread currentThread],i);
         });
     }
     NSLog(@"global_queue_sync_end");
 }

 //全局隊(duì)列異步
 - (void)globalAsyncMethod{
     //獲取全局隊(duì)列
      dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     //執(zhí)行任務(wù)
     for (int i = 0; i < 10; ++i) {
         dispatch_async(queue, ^{
             NSLog(@"global_queue_async%@---->%d----",[NSThread currentThread],i);
         });
     }
     NSLog(@"global_queue_async_end");
 }
全局隊(duì)列 同步執(zhí)行結(jié)果:
2016-11-03 19:06:02.650 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->0----
2016-11-03 19:06:02.651 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->1----
2016-11-03 19:06:02.651 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->2----
2016-11-03 19:06:02.651 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->3----
2016-11-03 19:06:02.651 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->4----
2016-11-03 19:06:02.651 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->5----
2016-11-03 19:06:02.652 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->6----
2016-11-03 19:06:02.652 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->7----
2016-11-03 19:06:02.652 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->8----
2016-11-03 19:06:02.652 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->9----
2016-11-03 19:06:02.652 ThreadDemo[27347:5324064] global_queue_sync_end
全局隊(duì)列 異步執(zhí)行結(jié)果:
2016-11-03 19:12:00.242 ThreadDemo[27430:5333537] global_queue_async_end
2016-11-03 19:12:00.242 ThreadDemo[27430:5334057] global_queue_async<NSThread: 0x608000266100>{number = 5, name = (null)}---->0----
2016-11-03 19:12:00.242 ThreadDemo[27430:5334053] global_queue_async<NSThread: 0x600000263c80>{number = 6, name = (null)}---->1----
2016-11-03 19:12:00.242 ThreadDemo[27430:5334056] global_queue_async<NSThread: 0x600000263cc0>{number = 7, name = (null)}---->2----
2016-11-03 19:12:00.242 ThreadDemo[27430:5334063] global_queue_async<NSThread: 0x608000268500>{number = 8, name = (null)}---->3----
2016-11-03 19:12:00.242 ThreadDemo[27430:5334064] global_queue_async<NSThread: 0x600000263b80>{number = 9, name = (null)}---->4----
2016-11-03 19:12:00.243 ThreadDemo[27430:5334057] global_queue_async<NSThread: 0x608000266100>{number = 5, name = (null)}---->5----
2016-11-03 19:12:00.243 ThreadDemo[27430:5334053] global_queue_async<NSThread: 0x600000263c80>{number = 6, name = (null)}---->7----
2016-11-03 19:12:00.243 ThreadDemo[27430:5334065] global_queue_async<NSThread: 0x600000073600>{number = 10, name = (null)}---->6----
2016-11-03 19:12:00.243 ThreadDemo[27430:5334056] global_queue_async<NSThread: 0x600000263cc0>{number = 7, name = (null)}---->8----
2016-11-03 19:12:00.243 ThreadDemo[27430:5334066] global_queue_async<NSThread: 0x608000267d40>{number = 11, name = (null)}---->9----

4. 主隊(duì)列(Main Dispatch Queue)

主隊(duì)列基本知識(shí)
  • dispatch_get_main_queue()函數(shù)來獲取
  • 專門用來在主線程上調(diào)度任務(wù)的隊(duì)列
  • 不會(huì)開啟線程
  • 以先進(jìn)先出的方式补箍,在主線程空閑時(shí)才會(huì)調(diào)度隊(duì)列中的任務(wù)在主線程執(zhí)行
  • 如果當(dāng)前主線程正在有任務(wù)執(zhí)行改执,那么無論主隊(duì)列中當(dāng)前被添加了什么任務(wù),都不會(huì)被調(diào)度
主隊(duì)列同步和異步執(zhí)行Demo
 #pragma mark -主隊(duì)列同步和主隊(duì)列異步
 //主隊(duì)列同步
 - (void)mainSyncMethod{
     //獲取主隊(duì)列
     dispatch_queue_t queue = dispatch_get_main_queue();
     //執(zhí)行任務(wù)
     for (int i = 0; i < 10; ++i) {
         dispatch_sync(queue, ^{
             NSLog(@"main_queue_sync%@---->%d----",[NSThread currentThread],i);
         });
     }
     NSLog(@"main_queue_sync_end");
 }

 //主隊(duì)列異步
 - (void)mainAsyncMethod{
     //獲取主隊(duì)列
     dispatch_queue_t queue = dispatch_get_main_queue();
     //執(zhí)行任務(wù)
     for (int i = 0; i < 10; ++i) {
         dispatch_async(queue, ^{
            NSLog(@"main_queue_async%@---->%d----",[NSThread currentThread],i);
         });
     }
     NSLog(@"main_queue_async_end");
 }
主隊(duì)列 同步執(zhí)行結(jié)果:
主線程和主隊(duì)列相互等待造成死鎖坑雅,程序會(huì)直接卡死辈挂!
原因:源代碼在Main Dispatch Queue 即主隊(duì)列中執(zhí)行指定的block任務(wù),并等待其結(jié)束裹粤。而其實(shí)在主線程中正在執(zhí)行這些源代碼终蒂,所以無法執(zhí)行追加到Main Dispatch Queue 的block任務(wù)。
下面例子也一樣:
dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        dispatch_sync(queue, ^{
            NSLog(@"main_queue_sync%@----",[NSThread currentThread]);
        });
    });

主隊(duì)列 異步執(zhí)行結(jié)果:
2016-11-03 19:45:38.154 ThreadDemo[27501:5349956] main_queue_async_end
2016-11-03 19:45:38.155 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->0----
2016-11-03 19:45:38.155 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->1----
2016-11-03 19:45:38.155 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->2----
2016-11-03 19:45:38.155 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->3----
2016-11-03 19:45:38.155 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->4----
2016-11-03 19:45:38.156 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->5----
2016-11-03 19:45:38.156 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->6----
2016-11-03 19:45:38.156 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->7----
2016-11-03 19:45:38.156 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->8----
2016-11-03 19:45:38.156 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->9----

5.延遲執(zhí)行(dispatch_after)

  • 在GCD中我們使用dispatch_after()函數(shù)來延遲執(zhí)行隊(duì)列中的任務(wù), dispatch_after()是異步執(zhí)行隊(duì)列中的任務(wù)的遥诉,也就是說使用dispatch_after()來執(zhí)行隊(duì)列中的任務(wù)不會(huì)阻塞當(dāng)前任務(wù)拇泣。等到延遲時(shí)間到了以后就會(huì)開辟一個(gè)新的線程然后執(zhí)行隊(duì)列中的任務(wù)。
  • dispatch_after(dispatch_time_t when,dispatch_queue_t queue,dispatch_block_t block);來創(chuàng)建
  • 經(jīng)過我的猜測測試(看不到源碼)矮锈,你們也思考一下這個(gè)延遲函數(shù)的實(shí)現(xiàn)過程霉翔。底層實(shí)現(xiàn)應(yīng)該是dispath_async函數(shù)追加block到Main Dispatch Queue等相應(yīng)隊(duì)列,偽代碼如下(以Main Dispatch Queue為例):
 dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
 delay(2){
 dispatch_async(queue, ^{
     dispatch_async(dispatch_get_main_queue(), ^{
     add task to mainQueue
    });
  });
 }
延遲執(zhí)行(dispatch_after)Demo
#pragma mark -  延遲執(zhí)行
 - (void)GCDAfterRunMethod{
     // 循環(huán)5次
     for (int i =0; i < 10000; i++ ) {
         NSLog(@"let's go %d",i);
         // 設(shè)置2秒后執(zhí)行block
         dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC));
         dispatch_after(time, dispatch_get_main_queue(), ^{
             NSLog(@"This is my %d number!%@",i,[NSThread currentThread]);
         });
     }
       //等價(jià)于下面實(shí)現(xiàn)
 //    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
 //    for (int i = 0; i < 10000; i++) {  //        NSLog(@"let's go %d",i);
 //        dispatch_async(queue, ^{
 //           dispatch_async(dispatch_get_main_queue(), ^{  //                NSLog(@"This is my %d number!%@",i,[NSThread currentThread]);
 //           });
 //        });
 //    }
 }
注意:
  • dispatch_after(dispatch_time_t when,dispatch_queue_t queue,dispatch_block_t block);
  • 第二個(gè)參數(shù):指定要追加處理的Dispatch Queue
  • 第三個(gè)參數(shù):指定要執(zhí)行處理的Block
  • 第一個(gè)參數(shù):指定時(shí)間用的dispatch_time_t類型的值苞笨,該值是使用dispatch_time函數(shù)或者dispatch_walltime函數(shù)生成
    1.dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC));
    里面有兩個(gè)參數(shù):
  參數(shù)1獲取指定的時(shí)間開始债朵,通常為DISPATCH_TIME_NOW,定義:
  #define DISPATCH_TIME_NOW (0ull)//現(xiàn)在
  #define DISPATCH_TIME_FOREVER (~0ull)//永遠(yuǎn)猫缭,意味著你用它你的任務(wù)永遠(yuǎn)不會(huì)執(zhí)行了葱弟!
參數(shù)2是從參數(shù)1延遲指定的時(shí)間來執(zhí)行任務(wù),也是一個(gè)時(shí)間
#define NSEC_PER_SEC 1000000000ull
#define NSEC_PER_MSEC 1000000ull
#define USEC_PER_SEC 1000000ull
#define NSEC_PER_USEC 1000ull
ull是C語言的數(shù)值字面量猜丹,是顯示表明類型是使用的字符串(表示“unsigned long long”)
NSEC_PER_SEC 是秒的單位數(shù)量級(jí) 等價(jià)于1億納秒
上面代碼中提到的(int64_t)(2 * NSEC_PER_SEC))就是2秒了

2.使用dispatch_walltime函數(shù)生成dispatch_time_t,用于計(jì)算絕對(duì)時(shí)間芝加,例如在dispatch_after函數(shù)中指定2016年11月3日21時(shí)45分1秒這一絕對(duì)時(shí)間,可粗略的鬧鐘功能來使用。也就是到指定時(shí)間就會(huì)執(zhí)行任務(wù)

//由NSDate類對(duì)象獲取dispatch_time_t傳遞給dispatch_after函數(shù)使用
dispatch_time_t  getDispatchTimeByDate(NSDate *date){
NSTimeInterval interval;
double second,subSecond;
struct timespec time;
dispatch_time_t milestone;
   
interval = [date timeIntervalSince1970];
   
subSecond = modf(interval, &second);
time.tv_sec = second;
time.tv_nsec = subSecond * NSEC_PER_SEC;

milestone = dispatch_walltime(&time, 0);
return milestone;
}

6. 更改優(yōu)先級(jí)(dispatch_set_target_queue)

  • dispatch_queue_create函數(shù)生成的Dispatch Queue不管是 串行隊(duì)列(Serial Dispatch Queue) 還是 并發(fā)隊(duì)列(Concurrent Dispatch Queue) 藏杖,都是用與 默認(rèn)優(yōu)先級(jí)全局隊(duì)列(Global Dispatch Queue)相同執(zhí)行優(yōu)先級(jí)的線程将塑。而全局隊(duì)列工作方式與并發(fā)隊(duì)列工作方式完全一致!

  • dispatch_set_target_queue(dispatch_object_t object,dispatch_queue_t _Nullable queue);函數(shù)來更改隊(duì)列優(yōu)先級(jí)

    • 第一個(gè)參數(shù):指定要變更優(yōu)先級(jí)的隊(duì)列(要更改隊(duì)列)
    • 第二個(gè)參數(shù):指定第一個(gè)參數(shù)(隊(duì)列)要和我們預(yù)期隊(duì)列執(zhí)行相同優(yōu)先級(jí)的隊(duì)列(目標(biāo)隊(duì)列)

1. dispatch_set_target_queue第一個(gè)Demo:

 - (void)GCDSetTargetQueueMethod{
    
     dispatch_queue_t targetQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
    
     dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);
     dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT);
      //更改優(yōu)先級(jí)
     dispatch_set_target_queue(queue1, targetQueue);
    
     for (int i = 0; i < 6; i++) {
         dispatch_async(queue1, ^{
         NSLog(@"queue1-currentThread = %@-->%d",[NSThread currentThread],i);
         });
     }
     for (int i = 0; i < 6; i++) {
          dispatch_async(queue2, ^{
          NSLog(@"queue2-----currentThread = %@----->%d",[NSThread currentThread],i);
          });
     }
 } 
打印結(jié)果:
2016-11-04 11:14:57.034 ThreadDemo[28477:5530919] queue2-----currentThread = <NSThread: 0x60000007e0c0>{number = 11, name = (null)}----->1
2016-11-04 11:14:57.034 ThreadDemo[28477:5530920] queue2-----currentThread = <NSThread: 0x60000007a140>{number = 12, name = (null)}----->2
2016-11-04 11:14:57.034 ThreadDemo[28477:5530918] queue2-----currentThread = <NSThread: 0x60000007a100>{number = 10, name = (null)}----->0
2016-11-04 11:14:57.034 ThreadDemo[28477:5530919] queue2-----currentThread = <NSThread: 0x60000007e0c0>{number = 11, name = (null)}----->3
2016-11-04 11:14:57.034 ThreadDemo[28477:5530912] queue1-currentThread = <NSThread: 0x60000007ec00>{number = 9, name = (null)}-->0
2016-11-04 11:14:57.034 ThreadDemo[28477:5530920] queue2-----currentThread = <NSThread: 0x60000007a140>{number = 12, name = (null)}----->5
2016-11-04 11:14:57.034 ThreadDemo[28477:5530921] queue2-----currentThread = <NSThread: 0x60000007c340>{number = 13, name = (null)}----->4
2016-11-04 11:14:57.035 ThreadDemo[28477:5530912] queue1-currentThread = <NSThread: 0x60000007ec00>{number = 9, name = (null)}-->1
2016-11-04 11:14:57.036 ThreadDemo[28477:5530912] queue1-currentThread = <NSThread: 0x60000007ec00>{number = 9, name = (null)}-->2
2016-11-04 11:14:57.036 ThreadDemo[28477:5530912] queue1-currentThread = <NSThread: 0x60000007ec00>{number = 9, name = (null)}-->3
2016-11-04 11:14:57.036 ThreadDemo[28477:5530912] queue1-currentThread = <NSThread: 0x60000007ec00>{number = 9, name = (null)}-->4
2016-11-04 11:14:57.037 ThreadDemo[28477:5530912] queue1-currentThread = <NSThread: 0x60000007ec00>{number = 9, name = (null)}-->5
打印解釋:
  • queue1和queue2設(shè)置的目標(biāo)隊(duì)列是全局隊(duì)列(并發(fā)),也就是允許要更改的隊(duì)列可以開辟多條線程(可以超過一條)
  • 代碼中queue1變更和低優(yōu)先級(jí)的全局隊(duì)列一樣優(yōu)先級(jí)的串行隊(duì)列蝌麸,queue2是dispatch_queue_create創(chuàng)建和默認(rèn)優(yōu)先級(jí)的全局隊(duì)列一樣優(yōu)先級(jí)的并發(fā)隊(duì)列点寥。
  • queue1和queue2都是異步執(zhí)行,都會(huì)開辟線程来吩,queue2是并發(fā)隊(duì)列所以打印中看到有多個(gè)線程敢辩,并且任務(wù)之間也不是順序執(zhí)行。queue1是串行隊(duì)列弟疆,所以只會(huì)開辟一個(gè)線程戚长,任務(wù)會(huì)順序執(zhí)行。
  • queue2隊(duì)列的優(yōu)先級(jí)比queue1隊(duì)列的優(yōu)先級(jí)要高怠苔,從打印中可以看到queue2的確比queue1任務(wù)要普遍先執(zhí)行同廉。為什么要說普遍呢,因?yàn)閺慕Y(jié)果上看到queue1有一個(gè)任務(wù)是在queue2里任務(wù)沒有執(zhí)行完畢也執(zhí)行了柑司,為什么會(huì)出現(xiàn)這個(gè)問題呢迫肖??
在上面全局隊(duì)列中說到了優(yōu)先級(jí)的事情
因?yàn)閄NU內(nèi)核用于Global Dispatch Queue的線程并不能保證實(shí)時(shí)性攒驰,因此執(zhí)行優(yōu)先級(jí)知識(shí)大概的判斷和區(qū)分蟆湖,
所有我們不能完全依賴這個(gè)優(yōu)先級(jí)來做隊(duì)列的順序事情,否則會(huì)出現(xiàn)問題讼育!切記

2. dispatch_set_target_queue第一個(gè)Demo:

  • dispatch_set_target_queue除了能用來設(shè)置隊(duì)列的優(yōu)先級(jí)之外帐姻,還能夠創(chuàng)建隊(duì)列的執(zhí)行層次
    ,當(dāng)我們想讓不同隊(duì)列中的任務(wù)同步的執(zhí)行時(shí)奶段,我們可以創(chuàng)建一個(gè)串行隊(duì)列,然后將這些隊(duì)列的target指向新創(chuàng)建的隊(duì)列即可剥纷,比如:


    隊(duì)列的執(zhí)行層次.png
 - (void)GCDSetTargetQueueMethod{
     dispatch_queue_t targetQueue = dispatch_queue_create("targetQueue", DISPATCH_QUEUE_SERIAL);//目標(biāo)隊(duì)列
     dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);//串行隊(duì)列
     dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT);//并發(fā)隊(duì)列
     //設(shè)置參考
     dispatch_set_target_queue(queue1, targetQueue);
     dispatch_set_target_queue(queue2, targetQueue);
    
     for (int i = 0; i < 6; i++) {
       dispatch_async(queue1, ^{
           NSLog(@"queue1-currentThread = %@-->%d",[NSThread currentThread],i);
       });
   }
   for (int i = 0; i < 6; i++) {
         dispatch_async(queue2, ^{
             NSLog(@"queue2-currentThread = %@-->%d",[NSThread currentThread],i);
         });
     }
    
 }
打印結(jié)果:
2016-11-04 11:34:34.722 ThreadDemo[28551:5540844] queue1-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->0
2016-11-04 11:34:34.723 ThreadDemo[28551:5540844] queue1-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->1
2016-11-04 11:34:34.723 ThreadDemo[28551:5540844] queue1-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->2
2016-11-04 11:34:34.723 ThreadDemo[28551:5540844] queue1-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->3
2016-11-04 11:34:34.723 ThreadDemo[28551:5540844] queue1-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->4
2016-11-04 11:34:34.723 ThreadDemo[28551:5540844] queue1-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->5
2016-11-04 11:34:34.724 ThreadDemo[28551:5540844] queue2-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->0
2016-11-04 11:34:34.724 ThreadDemo[28551:5540844] queue2-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->1
2016-11-04 11:34:34.724 ThreadDemo[28551:5540844] queue2-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->2
2016-11-04 11:34:34.724 ThreadDemo[28551:5540844] queue2-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->3
2016-11-04 11:34:34.724 ThreadDemo[28551:5540844] queue2-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->4
2016-11-04 11:34:34.725 ThreadDemo[28551:5540844] queue2-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->5
打印解釋:
  • queue1和queue2設(shè)置的目標(biāo)隊(duì)列是串行隊(duì)列,也就是允許要更改的隊(duì)列可以開辟一條線程痹籍。
  • queue1和queue2優(yōu)先級(jí)一樣,他兩執(zhí)行順序相當(dāng)于一個(gè)串行隊(duì)列異步執(zhí)行晦鞋!
  • queue1和queue2隊(duì)列以targetQueue隊(duì)列為參照對(duì)象蹲缠,那么queue1和queue2中的任務(wù)將按照targetQueue的隊(duì)列處理。
  • 適用場景:一般都是把一個(gè)任務(wù)放到一個(gè)串行的queue中悠垛,如果這個(gè)任務(wù)被拆分了线定,被放置到多個(gè)串行的queue中,但實(shí)際還是需要這個(gè)任務(wù)同步執(zhí)行确买,那么就會(huì)有問題斤讥,因?yàn)槎鄠€(gè)串行queue之間是并行的。這時(shí)候dispatch_set_target_queue將起到作用湾趾。

** dispatch_set_target_queue小結(jié):**

  • dispatch_set_target_queue可以更改Dispatch Queue優(yōu)先級(jí)芭商。
  • dispatch_set_target_queue可以更改隊(duì)列的執(zhí)行層次派草,隊(duì)列里的任務(wù)將會(huì)按照目標(biāo)隊(duì)列(target Queue)的隊(duì)列來處理

7. 任務(wù)組Dispatch Group

  • GCD的任務(wù)組在開發(fā)中是經(jīng)常被使用到,當(dāng)你一組任務(wù)結(jié)束后再執(zhí)行一些操作時(shí)铛楣,使用任務(wù)組在合適不過了近迁。dispatch_group的職責(zé)就是當(dāng)隊(duì)列中的所有任務(wù)都執(zhí)行完畢后在去做一些操作,也就是說在任務(wù)組中執(zhí)行的隊(duì)列簸州,當(dāng)隊(duì)列中的所有任務(wù)都執(zhí)行完畢后就會(huì)發(fā)出一個(gè)通知來告訴用戶任務(wù)組中所執(zhí)行的隊(duì)列中的任務(wù)執(zhí)行完畢了鉴竭。關(guān)于將隊(duì)列放到任務(wù)組中執(zhí)行有兩種方式,一種是使用dispatch_group_async()函數(shù)岸浑,將隊(duì)列與任務(wù)組進(jìn)行關(guān)聯(lián)并自動(dòng)執(zhí)行隊(duì)列中的任務(wù)搏存。另一種方式是手動(dòng)的將隊(duì)列與組進(jìn)行關(guān)聯(lián)然后使用異步將隊(duì)列進(jìn)行執(zhí)行,也就是dispatch_group_enter()dispatch_group_leave()方法的使用助琐。下方就給出詳細(xì)的介紹祭埂。
1.隊(duì)列與組自動(dòng)關(guān)聯(lián)并執(zhí)行
  • 首先我們來介紹dispatch_group_async()函數(shù)的使用方式,該函數(shù)會(huì)將隊(duì)列與相應(yīng)的任務(wù)組進(jìn)行關(guān)聯(lián)兵钮,并且自動(dòng)執(zhí)行蛆橡。當(dāng)與任務(wù)組關(guān)聯(lián)的隊(duì)列中的任務(wù)都執(zhí)行完畢后,會(huì)通過dispatch_group_notify()函數(shù)發(fā)出通知告訴用戶任務(wù)組中的所有任務(wù)都執(zhí)行完畢了掘譬。使用通知的方式是不會(huì)阻塞當(dāng)前線程的泰演,如果你使用dispatch_group_wait()函數(shù),那么就會(huì)阻塞當(dāng)前線程葱轩,直到任務(wù)組中的所有任務(wù)都執(zhí)行完畢睦焕。
 //自動(dòng)執(zhí)行任務(wù)組
 - (void)GCDAutoDispatchGroupMethod{
     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     dispatch_group_t group = dispatch_group_create();
   
     for (int i = 0; i < 6; i++) {
           dispatch_group_async(group, queue, ^{
             NSLog(@"current Thread = %@----->%d",[NSThread currentThread],i);
         });
     }

     dispatch_group_notify(group, dispatch_get_main_queue(), ^{
         NSLog(@"current Thread = %@----->這是最后執(zhí)行",[NSThread   currentThread]);
     });
}
打印結(jié)果:
2016-11-04 15:11:34.010 ThreadDemo[29225:5641180] current Thread = <NSThread: 0x600000468200>{number = 5, name = (null)}----->2
2016-11-04 15:11:34.010 ThreadDemo[29225:5641193] current Thread = <NSThread: 0x60800007f900>{number = 3, name = (null)}----->0
2016-11-04 15:11:34.011 ThreadDemo[29225:5641438] current Thread = <NSThread: 0x608000467980>{number = 8, name = (null)}----->5
2016-11-04 15:11:34.010 ThreadDemo[29225:5641178] current Thread = <NSThread: 0x608000467640>{number = 6, name = (null)}----->3
2016-11-04 15:11:34.010 ThreadDemo[29225:5641177] current Thread = <NSThread: 0x6080004675c0>{number = 4, name = (null)}----->1
2016-11-04 15:11:34.010 ThreadDemo[29225:5641437] current Thread = <NSThread: 0x600000467f40>{number = 7, name = (null)}----->4
2016-11-04 15:11:34.011 ThreadDemo[29225:5641137] current Thread = <NSThread: 0x60800007e200>{number = 1, name = main}----->這是最后執(zhí)行
  • 上面的函數(shù)就是使用dispatch_group_async()函數(shù)將隊(duì)列與任務(wù)組進(jìn)行關(guān)聯(lián)并執(zhí)行。首先我們創(chuàng)建了一個(gè)全局隊(duì)列(并發(fā))靴拱,然后又創(chuàng)建了一個(gè)類型為dispatch_group_t的任務(wù)組group垃喊。使用dispatch_group_async()函數(shù)將兩者進(jìn)行關(guān)聯(lián)并執(zhí)行。使用dispatch_group_notify()函數(shù)進(jìn)行監(jiān)聽group中隊(duì)列的執(zhí)行結(jié)果袜炕,如果執(zhí)行完畢后本谜,我們就在主線程中對(duì)結(jié)果進(jìn)行處理。

  • dispatch_group_notify()函數(shù)有兩個(gè)參數(shù)一個(gè)是發(fā)送通知的group偎窘,另一個(gè)是處理返回結(jié)果的隊(duì)列乌助。

  • dispatch_group_async(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);函數(shù)與dispatch_async函數(shù)相同,都追加block到指定的Dispatch Queue中陌知,與dispatch_async不同的是指定生成的Dispatch Group為第一個(gè)參數(shù)他托。指定的block屬于指定的Dispatch Group,不是Dispatch Queue仆葡,切記赏参!

  • 無論向什么樣的Dispatch Queue中追加處理,使用Dispatch Group都可監(jiān)視這些處理執(zhí)行的結(jié)束。一旦檢測到所有處理執(zhí)行結(jié)束登刺,就可將結(jié)束的處理追加到Dispatch Queue中籽腕。這就是使用Dispatch Group的原因。

  • 在追加到Dispatch Group中的處理全部執(zhí)行結(jié)束時(shí)纸俭,代碼中使用的dispatch_group_notify函數(shù)會(huì)將執(zhí)行的Block追加到Dispatch Queue中皇耗,將第一個(gè)參數(shù)指定為要監(jiān)視的Dispatch Group。在追加到該Dispatch Group的全部處理執(zhí)行結(jié)束時(shí)揍很,將第三個(gè)參數(shù)的Block追加到第二個(gè)參數(shù)的Dispatch Queue中郎楼。在dispatch_group_notify函數(shù)中不管指定什么樣的Dispatch Queue,屬于Dispatch Group的全部處理在追加指定的Block時(shí)都已執(zhí)行結(jié)束窒悔。

  • 另外呜袁,在Dispatch Group中也可以使用dispatch_group_wait函數(shù)僅等待全部處理執(zhí)行結(jié)束。

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_wait(group, DISPATCH_TIME_FOREVER);

  • dispatch_group_wait函數(shù)的第二個(gè)參數(shù)指定為等待時(shí)間(超時(shí))简珠。它屬于dispatch_time_t類型的值阶界。代碼中使用的DISPATCH_TIME_FOREVER,意味著永久等待聋庵。只要屬于Dispatch Group的操作尚未執(zhí)行結(jié)束膘融,就會(huì)一直等待,中途不能取消祭玉。

    指定等待時(shí)間為1微秒時(shí)氧映,應(yīng)做如下處理:

   //等待group處理結(jié)束
//    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
   dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1*USEC_PER_SEC));//1微秒
   long result = dispatch_group_wait(group, time);
   if (result == 0) {
       //屬于Dispatch Group 的block任務(wù)全部處理結(jié)束
       NSLog(@"Dispatch Group全部處理完畢");

   }else{
       //屬于Dispatch Group 的block任務(wù)還在處理中
       NSLog(@"Dispatch Group正在處理");
   }

  • 如果dispatch_group_wait函數(shù)的返回值不為0,就意味著雖然經(jīng)過了指定的時(shí)間脱货,但屬于Dispatch Group的某一個(gè)處理還在執(zhí)行中岛都。如果返回值為0,那么全部處理執(zhí)行結(jié)束振峻。當(dāng)?shù)却龝r(shí)間為DISPATCH_TIME_FOREVER臼疫,由dispatch_group_wait函數(shù)返回時(shí),屬于Dispatch Group的處理必定全部執(zhí)行結(jié)束扣孟,因此返回值恒為0多矮。

  • 這里的“等待”是什么意思?這意味著一旦調(diào)用dispatch_group_wait函數(shù)哈打,該函數(shù)就處于調(diào)用的狀態(tài)而不返回。即執(zhí)行dispatch_group_wait函數(shù)的現(xiàn)在的線程(當(dāng)前線程)停止讯壶。在經(jīng)過dispatch_group_wait函數(shù)中指定的時(shí)間或?qū)儆谥付―ispatch Group的處理全部執(zhí)行結(jié)束之前料仗,執(zhí)行該函數(shù)的線程停止,屬于阻塞狀態(tài)伏蚊。

  • 指定DISPACH_TIME_NOW立轧,則不用任何等待即可判定屬于Dispatch Group的處理是否執(zhí)行結(jié)束。

long result = diaptach_group_wait(group, DISPACH_TIME_NOW);
  • 在主線程的RunLoop的每次循環(huán)中,可檢查執(zhí)行是否結(jié)束氛改,從而不消耗多余的等待時(shí)間帐萎,雖然這樣有額可以,但一般在這種情況下胜卤,還是推薦用dispatch_group_notify函數(shù)追加結(jié)束處理到Main Dispatch Queue中疆导。這是因?yàn)?code>dispatch_group_notify函數(shù)可以簡化代碼。并且如果你用了diaptach_group_wait等待時(shí)間過長葛躏,中間不能取消隊(duì)列任務(wù)這就很坑了澈段!
2. 隊(duì)列與組手動(dòng)關(guān)聯(lián)并執(zhí)行
  • 接下來我們將手動(dòng)的管理任務(wù)組與隊(duì)列中的關(guān)系,也就是不使用dispatch_group_async()函數(shù)舰攒。我們使用dispatch_group_enter()dispatch_group_leave()函數(shù)將隊(duì)列中的每次任務(wù)加入到到任務(wù)組中败富。首先我們使用dispatch_group_enter()函數(shù)進(jìn)入到任務(wù)組中,然后異步執(zhí)行隊(duì)列中的任務(wù)摩窃,最后使用dispatch_group_leave()函數(shù)離開任務(wù)組即可兽叮。下面的函數(shù)中我們使用了dispatch_group_wait()函數(shù),該函數(shù)的職責(zé)就是阻塞當(dāng)前線程猾愿,來等待任務(wù)組中的任務(wù)執(zhí)行完畢鹦聪。該函數(shù)的第一個(gè)參數(shù)是所要等待的group,第二個(gè)參數(shù)是等待超時(shí)時(shí)間匪蟀,此處我們設(shè)置的是DISPATCH_TIME_FOREVER椎麦,就說明等待任務(wù)組的執(zhí)行永不超時(shí),直到任務(wù)組中所有任務(wù)執(zhí)行完畢材彪。
//手動(dòng)執(zhí)行任務(wù)組
 - (void)GCDManualDispatchGroupMethod{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    
    for (int i = 0; i < 6; i++) {
        
        dispatch_group_enter(group);//進(jìn)入隊(duì)列組
        
        dispatch_async(queue, ^{
            NSLog(@"current Thread = %@----->%d",[NSThread currentThread],i);
            
            dispatch_group_leave(group);//離開隊(duì)列組
        });
    }
    
    long result = dispatch_group_wait(group, DISPATCH_TIME_FOREVER);//阻塞當(dāng)前線程观挎,直到所有任務(wù)執(zhí)行完畢才會(huì)繼續(xù)往下執(zhí)行
    if (result == 0) {
        //屬于Dispatch Group 的block任務(wù)全部處理結(jié)束
        NSLog(@"Dispatch Group全部處理完畢");

    }else{
        //屬于Dispatch Group 的block任務(wù)還在處理中
        NSLog(@"Dispatch Group正在處理");
    }
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"current Thread = %@----->這是最后執(zhí)行",[NSThread currentThread]);
    });
 }
打印結(jié)果:dispatch_group_wait()函數(shù)下方的print()函數(shù)在所有任務(wù)執(zhí)行完畢之前是不會(huì)被調(diào)用的,因?yàn)?code>dispatch_group_wait()會(huì)將當(dāng)前線程進(jìn)行阻塞段化。當(dāng)然雖然是手動(dòng)的將隊(duì)列與任務(wù)組進(jìn)行關(guān)聯(lián)的嘁捷,感覺display_group_notify()函數(shù)還是好用的。
2016-11-04 16:19:13.802 ThreadDemo[29402:5678525] current Thread = <NSThread: 0x600000271780>{number = 5, name = (null)}----->2
2016-11-04 16:19:13.802 ThreadDemo[29402:5678527] current Thread = <NSThread: 0x608000077300>{number = 3, name = (null)}----->0
2016-11-04 16:19:13.802 ThreadDemo[29402:5678524] current Thread = <NSThread: 0x60800007d840>{number = 4, name = (null)}----->1
2016-11-04 16:19:13.803 ThreadDemo[29402:5678760] current Thread = <NSThread: 0x600000271cc0>{number = 8, name = (null)}----->5
2016-11-04 16:19:13.802 ThreadDemo[29402:5678545] current Thread = <NSThread: 0x60800007d000>{number = 6, name = (null)}----->3
2016-11-04 16:19:13.802 ThreadDemo[29402:5678544] current Thread = <NSThread: 0x60800007d040>{number = 7, name = (null)}----->4
2016-11-04 16:19:13.803 ThreadDemo[29402:5678489] Dispatch Group全部處理完畢
2016-11-04 16:19:13.804 ThreadDemo[29402:5678489] current Thread = <NSThread: 0x600000069dc0>{number = 1, name = main}----->這是最后執(zhí)行

8. 柵欄任務(wù)Dispatch_barrier_async

  • barrier顧名思義柵欄显熏、障礙物的意思雄嚣!
    在訪問數(shù)據(jù)庫或文件時(shí),使用Serial Dispatch Queue可避免數(shù)據(jù)競爭的問題喘蟆。

    寫入處理確實(shí)不可與其他的寫入處理以及包含讀取處理的其他某些處理并行執(zhí)行缓升。但是如果讀取處理只是與讀取處理并行執(zhí)行,那么多個(gè)并行執(zhí)行就不會(huì)發(fā)生問題蕴轨。

    也就是說港谊,為了高效率地進(jìn)行訪問,讀取處理追加到Concurrent Dispatch Queue中橙弱,寫入出路在任何一個(gè)讀取處理沒有執(zhí)行的狀態(tài)下歧寺,追加到Serial Dispatch Queue中即可(在寫入處理結(jié)束之前燥狰,讀取處理不可執(zhí)行)。

    雖然利用Dispatch Group和dispatch_set_target_queue函數(shù)也可實(shí)現(xiàn)斜筐,但代碼會(huì)很復(fù)雜龙致。有興趣的可以自己嘗試寫寫!
    CD為我們提供了更為聰明的解決辦法——dispatch_barrier_async函數(shù)顷链。該函數(shù)同dispatch_queue_create函數(shù)生成的Concurrent Dispatch Queue一起使用目代。

 #pragma mark - Dispatch_barrier_async
 - (void)GCDBarrierAsyncMethod{
    
    dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    void(^blk1_reading)(void) = ^{
         NSLog(@"blk1---reading");
    };
    
    void(^blk2_reading)(void) = ^{
        NSLog(@"blk2---reading");
    };
    void(^blk3_reading)(void) = ^{
        NSLog(@"blk3---reading");
    };
    void(^blk4_reading)(void) = ^{
        NSLog(@"blk4---reading");
    };
    void(^blk_writing)(void) = ^{
        NSLog(@"blk---writing");
    };
        
    dispatch_async(concurrentQueue, blk1_reading);
    dispatch_async(concurrentQueue, blk2_reading);
    
    //添加追加操作,,會(huì)等待b1和b2全部執(zhí)行結(jié)束,執(zhí)行完成追加操作b蕴潦,才會(huì)繼續(xù)并發(fā)執(zhí)行下面操作
    dispatch_barrier_async(concurrentQueue, blk_writing);
    
    dispatch_async(concurrentQueue, blk3_reading);
    dispatch_async(concurrentQueue, blk4_reading);

}
打印結(jié)果:
2016-11-04 17:02:13.202 ThreadDemo[29492:5700974] blk2---reading
2016-11-04 17:02:13.202 ThreadDemo[29492:5700972] blk1---reading
2016-11-04 17:02:13.203 ThreadDemo[29492:5700972] blk---writing
2016-11-04 17:02:13.203 ThreadDemo[29492:5700972] blk3---reading
2016-11-04 17:02:13.203 ThreadDemo[29492:5700974] blk4---reading
  • 使用Concurrent Dispatch Queuedispatch_barrier_async函數(shù)可實(shí)現(xiàn)高效率的數(shù)據(jù)庫訪問和文件訪問,dispatch_barrier_async函數(shù)還是比較好理解的像啼。

9. 循環(huán)執(zhí)行dispatch_apply

  • dispatch_apply()函數(shù)是用來循環(huán)來執(zhí)行隊(duì)列中的任務(wù)的,使用方式為:dispatch_apply(循環(huán)次數(shù), 任務(wù)所在的隊(duì)列) { 要循環(huán)執(zhí)行的任務(wù) }潭苞。使用該函數(shù)循環(huán)執(zhí)行并行隊(duì)列中的任務(wù)時(shí)忽冻,會(huì)開辟新的線程,不過有可能會(huì)在當(dāng)前線程中執(zhí)行一些任務(wù)此疹。而使用dispatch_apply()執(zhí)行串行隊(duì)列中的任務(wù)時(shí)僧诚,會(huì)在當(dāng)前線程中執(zhí)行。無論是使用并行隊(duì)列還是串行隊(duì)列蝗碎,dispatch_apply()都會(huì)阻塞當(dāng)前執(zhí)行函數(shù)線程湖笨。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     dispatch_apply(10, queue, ^(size_t index){
     NSLog(@"%zu", index);
});
    
NSLog(@"done");
2016-11-04 17:24:25.819 ThreadDemo[29598:5715955] 2
2016-11-04 17:24:25.819 ThreadDemo[29598:5715904] 0
2016-11-04 17:24:25.819 ThreadDemo[29598:5716588] 1
2016-11-04 17:24:25.819 ThreadDemo[29598:5716640] 3
2016-11-04 17:24:25.820 ThreadDemo[29598:5715955] 4
2016-11-04 17:24:25.820 ThreadDemo[29598:5715904] 5
2016-11-04 17:24:25.820 ThreadDemo[29598:5716588] 6
2016-11-04 17:24:25.820 ThreadDemo[29598:5716640] 7
2016-11-04 17:24:25.820 ThreadDemo[29598:5715904] 9
2016-11-04 17:24:25.820 ThreadDemo[29598:5715955] 8
2016-11-04 17:24:25.820 ThreadDemo[29598:5715904] done
  • 輸出結(jié)果中最后的done必定在最后的位置上,這是因?yàn)閐ispatch_apply函數(shù)會(huì)等待全部處理執(zhí)行結(jié)束蹦骑,也就是阻塞當(dāng)前執(zhí)行函數(shù)線程慈省。

  • 另外,由于dispatch_apply函數(shù)也與dispatch_sync函數(shù)相同眠菇,會(huì)等待處理執(zhí)行結(jié)束(阻塞)边败,因此推薦在dispatch_async函數(shù)中非同步地執(zhí)行dispatch_apply函數(shù)。

#pragma mark - Dispatch_apply
 - (void)GCDDispatchApplyMethod{
   
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    void(^blk1_reading)(void) = ^{
        NSLog(@"blk1---reading");
    };
    
    void(^blk2_reading)(void) = ^{
        NSLog(@"blk2---reading");
    };
    void(^blk3_reading)(void) = ^{
        NSLog(@"blk3---reading");
    };
    void(^blk_writing)(void) = ^{
        NSLog(@"blk---writing");
    };

    NSMutableArray *array = [NSMutableArray new];
    [array addObject:blk1_reading];
    [array addObject:blk2_reading];
    [array addObject:blk3_reading];
    [array addObject:blk_writing];
    
    dispatch_async(queue, ^{
        dispatch_apply(array.count, queue, ^(size_t index) {
            void (^blk)(void) = [array objectAtIndex:index];
            blk();
            NSLog(@"%zu====%@",index,[array objectAtIndex:index]);
        });
        NSLog(@"全部執(zhí)行結(jié)束");
        dispatch_async(dispatch_get_main_queue(), ^{
            //在main Dispatch queue中執(zhí)行處理捎废,更新用戶界面等待
            NSLog(@"done");
        });
    });

}
打印結(jié)果:
2016-11-04 17:36:02.258 ThreadDemo[29635:5723967] blk3---reading
2016-11-04 17:36:02.258 ThreadDemo[29635:5723940] blk2---reading
2016-11-04 17:36:02.258 ThreadDemo[29635:5723929] blk1---reading
2016-11-04 17:36:02.258 ThreadDemo[29635:5723968] blk---writing
2016-11-04 17:36:02.259 ThreadDemo[29635:5723940] 1====<__NSGlobalBlock__: 0x102895af0>
2016-11-04 17:36:02.259 ThreadDemo[29635:5723967] 2====<__NSGlobalBlock__: 0x102895b30>
2016-11-04 17:36:02.259 ThreadDemo[29635:5723929] 0====<__NSGlobalBlock__: 0x102895ab0>
2016-11-04 17:36:02.259 ThreadDemo[29635:5723968] 3====<__NSGlobalBlock__: 0x102895b70>
2016-11-04 17:36:02.259 ThreadDemo[29635:5723940] 全部執(zhí)行結(jié)束
2016-11-04 17:36:02.259 ThreadDemo[29635:5723499] done

10. 隊(duì)列的掛起和喚醒

  • 隊(duì)列的掛起與喚醒相對(duì)較為簡單笑窜,如果你想對(duì)一個(gè)隊(duì)列中的任務(wù)的執(zhí)行進(jìn)行掛起,那么你就使用dispatch_suspend()函數(shù)即可登疗。如果你要喚醒某個(gè)掛起的隊(duì)列排截,那么你就可以使用dispatch_resum()函數(shù)。這兩個(gè)函數(shù)所需的參數(shù)都是你要掛起或者喚醒的隊(duì)列辐益,鑒于知識(shí)點(diǎn)的簡單性就不做過多的贅述了断傲。
#pragma mark -Dispatch_suspend/Dispatch_resume
- (void)GCDDispatch_suspend_resume{
    //系統(tǒng)默認(rèn)生成的,所以無法調(diào)用dispatch_resume()和dispatch_suspend()來控制執(zhí)行繼續(xù)或中斷智政。
    
    dispatch_queue_t queue1 = dispatch_queue_create("queue1", 0);
    dispatch_queue_t queue2 = dispatch_queue_create("queue2", 0);
    
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_async(queue1, ^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"%@-------%d",[NSThread currentThread],i);
            sleep(1);         
        }
    });
    
    dispatch_async(queue2, ^{
        NSLog(@"task2");
    });
    
    dispatch_group_async(group, queue1, ^{
        NSLog(@"task1 finished!");
    });
    dispatch_group_async(group, queue2, ^{
       dispatch_suspend(queue1);//掛起
       NSLog(@"task2 finished!掛起queue1");
       [NSThread sleepForTimeInterval:20.0];
       dispatch_resume(queue1);//喚醒隊(duì)列
        
    });
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    
    dispatch_async(queue1, ^{
        NSLog(@"task3");
    });
    dispatch_async(queue2, ^{
        NSLog(@"task4");
    });
}
打印結(jié)果:可以先思考一下打印結(jié)果
2016-11-04 17:59:41.219 ThreadDemo[29749:5738141] task2
2016-11-04 17:59:41.219 ThreadDemo[29749:5738138] <NSThread: 0x60000027c380>{number = 4, name = (null)}-------0
2016-11-04 17:59:41.220 ThreadDemo[29749:5738141] task2 finished!掛起queue1
2016-11-04 17:59:42.220 ThreadDemo[29749:5738138] <NSThread: 0x60000027c380>{number = 4, name = (null)}-------1
2016-11-04 17:59:43.223 ThreadDemo[29749:5738138] <NSThread: 0x60000027c380>{number = 4, name = (null)}-------2
2016-11-04 17:59:44.225 ThreadDemo[29749:5738138] <NSThread: 0x60000027c380>{number = 4, name = (null)}-------3
2016-11-04 17:59:45.230 ThreadDemo[29749:5738138] <NSThread: 0x60000027c380>{number = 4, name = (null)}-------4
2016-11-04 18:00:01.220 ThreadDemo[29749:5738141] task1 finished!
2016-11-04 18:00:01.220 ThreadDemo[29749:5738141] task3
2016-11-04 18:00:01.221 ThreadDemo[29749:5738769] task4

11. 信號(hào)量Dispatch Semaphore

當(dāng)并行執(zhí)行的處理更新數(shù)據(jù)時(shí)艳悔,會(huì)產(chǎn)出數(shù)據(jù)不一致的情況,有時(shí)應(yīng)用就會(huì)異常退出女仰〔履辏可以使用Serial Dispatch Queue 和 dispatch_barrier也可以處理這種情況,我們也可以使用信號(hào)量Dispatch Semaphor來更好的處理線程安全和同步的問題疾忍。

Dispatch Semaphore是持有計(jì)數(shù)的信號(hào)乔外。使用計(jì)數(shù)來實(shí)現(xiàn)該等待還是運(yùn)行功能。計(jì)數(shù)為0時(shí)等待一罩,計(jì)數(shù)為1或者大于1時(shí)杨幼,減去1而不是等待,就可以運(yùn)行聂渊。

其實(shí)信號(hào)量就是根據(jù)pv操作來實(shí)現(xiàn)的

  • p操作-1 v操作+1

信號(hào)量就是一個(gè)資源計(jì)數(shù)器差购,對(duì)信號(hào)量有兩個(gè)操作來達(dá)到互斥,分別是P和V操作汉嗽。

一般情況是這樣進(jìn)行臨界訪問或互斥訪問的: 設(shè)信號(hào)量值為1欲逃, 當(dāng)一個(gè)進(jìn)程1運(yùn)行時(shí),使用資源饼暑,進(jìn)行P操作稳析,即對(duì)信號(hào)量值減1,也就是資源數(shù)少了1個(gè)弓叛。這是信號(hào)量值為0彰居。系統(tǒng)中規(guī)定當(dāng)信號(hào)量值為0是,必須等待撰筷,直到信號(hào)量值不為零才能繼續(xù)操作陈惰。 這時(shí)如果進(jìn)程2想要運(yùn)行,那么也必須進(jìn)行P操作毕籽,但是此時(shí)信號(hào)量為0抬闯,所以無法減1,即不能P操作影钉,也就阻塞画髓。這樣就到到了進(jìn)程1排他訪問。 當(dāng)進(jìn)程1運(yùn)行結(jié)束后平委,釋放資源奈虾,進(jìn)行V操作。資源數(shù)重新加1廉赔,這是信號(hào)量的值變?yōu)?. 這時(shí)進(jìn)程2發(fā)現(xiàn)資源數(shù)不為0肉微,信號(hào)量能進(jìn)行P操作了,立即執(zhí)行P操作蜡塌。信號(hào)量值又變?yōu)?.次數(shù)進(jìn)程2咱有資源碉纳,排他訪問資源。 這就是信號(hào)量來控制互斥的原理

信號(hào)量為0則阻塞線程馏艾,大于0則不會(huì)阻塞劳曹。則我們通過改變信號(hào)量的值奴愉,來控制是否阻塞線程,從而達(dá)到線程同步铁孵。

- (void)GCDDispatchSemaphore{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
  //創(chuàng)建一個(gè)信號(hào)量dispatch
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    
    NSMutableArray *array = [NSMutableArray new];
    for (int i = 0; i < 10; i++) {
        dispatch_async(queue, ^{
            //一直等待信號(hào)量大于0
            dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, DISPATCH_TIME_FOREVER));
            
          //進(jìn)行排他控制的處理代碼...
          //將dispatch semphore的計(jì)數(shù)器減1 
            [array addObject:[NSNumber numberWithInteger:i]];
              
            //排他控制處理結(jié)束
            //將dispatch semphore的計(jì)數(shù)器加1    
            //如果有通過dispatch_semaphore_wait函數(shù)dispatch semphore的計(jì)數(shù)值增加的線程锭硼,等待就由最先等待的線程執(zhí)行                  
            dispatch_semaphore_signal(semaphore);
        });
        
        NSLog(@"%@",array);
    }
}
  • 創(chuàng)建一個(gè)信號(hào)量dispatch dispatch_semaphore_t dispatch_semaphore_create(long value);
  • 等待信號(hào)量longdispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);返回值和dispatch_group_wait函數(shù)相同,也可以通過下面進(jìn)行分支處理:
long  result = dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10*NSEC_PER_SEC)));
            
 if (result == 0){
      //進(jìn)行排他控制的處理代碼...
      //將dispatch semphore的計(jì)數(shù)器減1 
      [array addObject:[NSNumber numberWithInteger:i]];
              
      //排他控制處理結(jié)束
      //將dispatch semphore的計(jì)數(shù)器加1    
      //如果有通過dispatch_semaphore_wait函數(shù)dispatch semphore的計(jì)數(shù)值增加的線程蜕劝,等待就由最先等待的線程執(zhí)行                  
      dispatch_semaphore_signal(semaphore);
}else{
      //這個(gè)時(shí)候計(jì)數(shù)值為0檀头,在達(dá)到指定時(shí)間為止還是等待狀態(tài)。
        //處理邏輯....
}

  • 在進(jìn)行排他處理結(jié)束時(shí)岖沛,通過dispatch_semaphore_signal來講計(jì)數(shù)值加1

GCD總結(jié)

  1. 開不開線程由執(zhí)行任務(wù)的函數(shù)決定
  • 異步開暑始,異步是多線程的代名詞
  • 同步不開
  1. 開幾條線程由隊(duì)列決定
  • 串行隊(duì)列開一條線程(GCD會(huì)開一條,NSOperation Queue最大并發(fā)數(shù)為1時(shí)也可能開多條)
  • 并發(fā)隊(duì)列開多條線程婴削,具體能開的線程數(shù)量由底層線程池決定
  1. GCD的使用步驟
  • 1.創(chuàng)建block任務(wù)
  • 2.創(chuàng)建GCD隊(duì)列(串行和并發(fā))
  • 3.把block任務(wù)放到GCD隊(duì)列里廊镜,以異步或者同步方式執(zhí)行GCD隊(duì)列

結(jié)尾:

能看到這里的小伙伴都是真愛啊,內(nèi)容太多了馆蠕。學(xué)完這個(gè)你們多思考一下里面方法的聯(lián)系以及實(shí)現(xiàn)期升,好了今天的GCD就講到這里,中間有什么錯(cuò)誤歡迎你們批評(píng)指出!下一篇博客將帶你走進(jìn)NSOperation互躬。

喜歡的話就請點(diǎn)個(gè)喜歡加個(gè)關(guān)注_(樓主好無恥安チ蕖)??

ThreadDemo下載鏈接

參考書籍:Objective-C高級(jí)編程iOS與OS X多線程和內(nèi)存管理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市吼渡,隨后出現(xiàn)的幾起案子容为,更是在濱河造成了極大的恐慌,老刑警劉巖寺酪,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坎背,死亡現(xiàn)場離奇詭異,居然都是意外死亡寄雀,警方通過查閱死者的電腦和手機(jī)得滤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盒犹,“玉大人懂更,你說我怎么就攤上這事〖卑颍” “怎么了沮协?”我有些...
    開封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長卓嫂。 經(jīng)常有香客問我慷暂,道長,這世上最難降的妖魔是什么晨雳? 我笑而不...
    開封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任行瑞,我火速辦了婚禮奸腺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蘑辑。我一直安慰自己洋机,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開白布洋魂。 她就那樣靜靜地躺著,像睡著了一般喜鼓。 火紅的嫁衣襯著肌膚如雪副砍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天庄岖,我揣著相機(jī)與錄音豁翎,去河邊找鬼。 笑死隅忿,一個(gè)胖子當(dāng)著我的面吹牛心剥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播背桐,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼优烧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了链峭?” 一聲冷哼從身側(cè)響起畦娄,我...
    開封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎弊仪,沒想到半個(gè)月后熙卡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡励饵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年驳癌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片役听。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡颓鲜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出禾嫉,到底是詐尸還是另有隱情灾杰,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站檀葛,受9級(jí)特大地震影響工育,放射性物質(zhì)發(fā)生泄漏攀圈。R本人自食惡果不足惜昭娩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一凛篙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧栏渺,春花似錦呛梆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至霎终,卻和暖如春滞磺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背莱褒。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來泰國打工击困, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人广凸。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓阅茶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親谅海。 傳聞我的和親對(duì)象是個(gè)殘疾皇子脸哀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • Dispatch Queues dispatch queues是執(zhí)行任務(wù)的強(qiáng)大工具,允許你同步或異步地執(zhí)行任意代碼...
    YangPu閱讀 644評(píng)論 0 4
  • NSThread 第一種:通過NSThread的對(duì)象方法 NSThread *thread = [[NSThrea...
    攻城獅GG閱讀 797評(píng)論 0 3
  • 歡迎大家指出文章中需要改正或者需要補(bǔ)充的地方胁赢,我會(huì)及時(shí)更新企蹭,非常感謝。 一. 多線程基礎(chǔ) 1. 進(jìn)程 進(jìn)程是指在系...
    xx_cc閱讀 7,184評(píng)論 11 70
  • 原創(chuàng)內(nèi)容,轉(zhuǎn)載請注明出處: http://www.reibang.com/p/ac11fe7ef78c 前言 多線...
    抱緊我的小鯉魚閱讀 8,809評(píng)論 6 78
  • 從哪說起呢智末? 單純講多線程編程真的不知道從哪下嘴谅摄。。 不如我直接引用一個(gè)最簡單的問題系馆,以這個(gè)作為切入點(diǎn)好了 在ma...
    Mr_Baymax閱讀 2,752評(píng)論 1 17