GCD多線程應(yīng)用

概念

在GCD中有兩個重要的概念:任務(wù)和隊列狞尔。

任務(wù)

所要執(zhí)行的操作潘靖。任務(wù)有兩種執(zhí)行方式:同步執(zhí)行和異步執(zhí)行降淮。

  • 同步執(zhí)行:
    1. 會阻塞當(dāng)前線程逐沙,直到任務(wù)執(zhí)行完成才會返回當(dāng)前線程繼續(xù)運行
    2. 不具備開啟新線程的能力
  • 異步執(zhí)行:
    1. 不會阻塞當(dāng)前線程洛史,會立即返回當(dāng)前線程繼續(xù)運行
    2. 具備開啟新線程的能力

隊列

用于存放任務(wù)。隊列有兩種:串行隊列和并發(fā)隊列酱吝。

  • 串行隊列:

    1. 任務(wù)執(zhí)行遵循先進(jìn)先出的順序也殖,下一個任務(wù)在上一個任務(wù)執(zhí)行完成后開始執(zhí)行
    2. 創(chuàng)建方式(兩種)
    dispatch_queue_t serialQueue = dispatch_queue_create("com.apress.mySerialQueue", nil) ;
    dispatch_queue_t serialQueue = dispatch_queue_create("com.apress.mySerialQueue", DISPATCH_QUEUE_SERIAL) ;
    
  • 并發(fā)隊列:

    1. 任務(wù)執(zhí)行遵循先進(jìn)先出的順序,下一個任務(wù)可以在上一個任務(wù)執(zhí)行完成前開始執(zhí)行
    2. 創(chuàng)建方式
    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.appress.myConcurrentQueue",DISPATCH_QUEUE_CONCURRENT) ;
    
    1. 系統(tǒng)提供了四種全局的并發(fā)隊列务热,這些隊列通過優(yōu)先級加以區(qū)別忆嗜。高優(yōu)先級隊列中的任務(wù)會比在默認(rèn)或低優(yōu)先級隊列中的任務(wù)先執(zhí)行,而默認(rèn)級別隊列的優(yōu)先級又高于低優(yōu)先級隊列崎岂。被設(shè)置成后臺級別的隊列捆毫,它會等待所有比它級別高的隊列中的任務(wù)執(zhí)行完或CPU空閑的時候才會執(zhí)行自己的任務(wù)
    dispatch_queue_t  concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) ;
    
    字段 優(yōu)先級
    DISPATCH_QUEUE_PRIORITY_HIGH 高優(yōu)先級
    DISPATCH_QUEUE_PRIORITY_DEFAULT 默認(rèn)優(yōu)先級
    DISPATCH_QUEUE_PRIORITY_LOW 低優(yōu)先級
    DISPATCH_QUEUE_PRIORITY_BACKGROUND 后臺級別
  • 主隊列:
    除了串行隊列和并發(fā)隊列,還有一種特殊的隊列——主隊列冲甘。

    1. 是串行隊列
    2. 所有放在主隊列中的任務(wù)都會放到主線程中執(zhí)行
    3. 可通過dispatch_get_main_queue()獲得

GCD的多線程使用

使用步驟

  1. 創(chuàng)建隊列
  2. 向隊列中添加任務(wù):
    • 通過dispatch_async進(jìn)行異步添加
    • 通過dispatch_sync進(jìn)行同步添加

使用方式

由于存在不同的隊列和任務(wù)執(zhí)行方式绩卤,因此有多種組合方式來使用。

  1. 并發(fā)隊列+同步執(zhí)行
- (void)test {
    NSLog(@"=============begin") ;
    dispatch_queue_t myQueue = dispatch_queue_create("com.appress.myQueue",DISPATCH_QUEUE_CONCURRENT) ;
    dispatch_sync(myQueue, ^{
        for(int i = 0; i < 2; i++) {
            NSLog(@"1=========%@",[NSThread currentThread]) ;
        }
    }) ;
    dispatch_sync(myQueue, ^{
        for(int i = 0; i < 2; i++) {
            NSLog(@"2=========%@",[NSThread currentThread]) ;
        }
    }) ;
    dispatch_sync(myQueue, ^{
        for(int i = 0; i < 2; i++) {
            NSLog(@"3=========%@",[NSThread currentThread]) ;
        }
    }) ;
    NSLog(@"=============end") ;
}

打印結(jié)果為:

2017-05-03 14:59:35.976 test[1022:28719] =============begin
2017-05-03 14:59:35.977 test[1022:28719] 1=========<NSThread: 0x600000071240>{number = 1, name = main}
2017-05-03 14:59:35.977 test[1022:28719] 1=========<NSThread: 0x600000071240>{number = 1, name = main}
2017-05-03 14:59:35.977 test[1022:28719] 2=========<NSThread: 0x600000071240>{number = 1, name = main}
2017-05-03 14:59:35.977 test[1022:28719] 2=========<NSThread: 0x600000071240>{number = 1, name = main}
2017-05-03 14:59:35.977 test[1022:28719] 3=========<NSThread: 0x600000071240>{number = 1, name = main}
2017-05-03 14:59:35.977 test[1022:28719] 3=========<NSThread: 0x600000071240>{number = 1, name = main}
2017-05-03 14:59:35.978 test[1022:28719] =============end
  • 不會開啟新線程江醇,而是在當(dāng)前線程執(zhí)行
  • 任務(wù)按照順序一個一個執(zhí)行
  • 會阻塞當(dāng)前線程
  1. 并發(fā)隊列+異步執(zhí)行
- (void)test {
    NSLog(@"=============begin") ;
    dispatch_queue_t myQueue = dispatch_queue_create("com.appress.myQueue",DISPATCH_QUEUE_CONCURRENT) ;
    dispatch_async(myQueue, ^{
        for(int i = 0; i < 2; i++) {
            NSLog(@"1=========%@",[NSThread currentThread]) ;
        }
    }) ;
    dispatch_async(myQueue, ^{
        for(int i = 0; i < 2; i++) {
            NSLog(@"2=========%@",[NSThread currentThread]) ;
        }
    }) ;
    dispatch_async(myQueue, ^{
        for(int i = 0; i < 2; i++) {
            NSLog(@"3=========%@",[NSThread currentThread]) ;
        }
    }) ;
    NSLog(@"=============end") ;
}

打印結(jié)果為:

2017-05-03 15:04:37.047 test[1064:39634] =============begin
2017-05-03 15:04:37.047 test[1064:39634] =============end
2017-05-03 15:04:37.048 test[1064:39685] 2=========<NSThread: 0x60800007bc00>{number = 4, name = (null)}
2017-05-03 15:04:37.048 test[1064:39690] 1=========<NSThread: 0x60800007bd00>{number = 3, name = (null)}
2017-05-03 15:04:37.048 test[1064:39684] 3=========<NSThread: 0x60800007bfc0>{number = 5, name = (null)}
2017-05-03 15:04:37.048 test[1064:39685] 2=========<NSThread: 0x60800007bc00>{number = 4, name = (null)}
2017-05-03 15:04:37.048 test[1064:39690] 1=========<NSThread: 0x60800007bd00>{number = 3, name = (null)}
2017-05-03 15:04:37.049 test[1064:39684] 3=========<NSThread: 0x60800007bfc0>{number = 5, name = (null)}
  • 開啟了多個新線程濒憋,并且在各自的新線程中執(zhí)行
  • 任務(wù)交替著同時執(zhí)行
  • 不會阻塞當(dāng)前線程
  1. 串行隊列+同步執(zhí)行
- (void)test {
    NSLog(@"=============begin") ;
    dispatch_queue_t myQueue = dispatch_queue_create("com.appress.myQueue",nil) ;
    dispatch_sync(myQueue, ^{
        for(int i = 0; i < 2; i++) {
            NSLog(@"1=========%@",[NSThread currentThread]) ;
        }
    }) ;
    dispatch_sync(myQueue, ^{
        for(int i = 0; i < 2; i++) {
            NSLog(@"2=========%@",[NSThread currentThread]) ;
        }
    }) ;
    dispatch_sync(myQueue, ^{
        for(int i = 0; i < 2; i++) {
            NSLog(@"3=========%@",[NSThread currentThread]) ;
        }
    }) ;
    NSLog(@"=============end") ;
}

打印結(jié)果為:

2017-05-03 15:10:33.497 test[1133:50233] =============begin
2017-05-03 15:10:33.497 test[1133:50233] 1=========<NSThread: 0x608000063800>{number = 1, name = main}
2017-05-03 15:10:33.498 test[1133:50233] 1=========<NSThread: 0x608000063800>{number = 1, name = main}
2017-05-03 15:10:33.498 test[1133:50233] 2=========<NSThread: 0x608000063800>{number = 1, name = main}
2017-05-03 15:10:33.498 test[1133:50233] 2=========<NSThread: 0x608000063800>{number = 1, name = main}
2017-05-03 15:10:33.499 test[1133:50233] 3=========<NSThread: 0x608000063800>{number = 1, name = main}
2017-05-03 15:10:33.499 test[1133:50233] 3=========<NSThread: 0x608000063800>{number = 1, name = main}
2017-05-03 15:10:33.499 test[1133:50233] =============end
  • 不會開啟新線程,而是在當(dāng)前線程執(zhí)行
  • 任務(wù)按照順序一個一個執(zhí)行
  • 會阻塞當(dāng)前線程
  1. 串行隊列+異步執(zhí)行
- (void)test {
    NSLog(@"=============begin") ;
    dispatch_queue_t myQueue = dispatch_queue_create("com.appress.myQueue",nil) ;
    dispatch_async(myQueue, ^{
        for(int i = 0; i < 2; i++) {
            NSLog(@"1=========%@",[NSThread currentThread]) ;
        }
    }) ;
    dispatch_async(myQueue, ^{
        for(int i = 0; i < 2; i++) {
            NSLog(@"2=========%@",[NSThread currentThread]) ;
        }
    }) ;
    dispatch_async(myQueue, ^{
        for(int i = 0; i < 2; i++) {
            NSLog(@"3=========%@",[NSThread currentThread]) ;
        }
    }) ;
    NSLog(@"=============end") ;
}

打印結(jié)果為:

2017-05-03 15:13:35.786 test[1168:56495] =============begin
2017-05-03 15:13:35.787 test[1168:56495] =============end
2017-05-03 15:13:35.787 test[1168:56601] 1=========<NSThread: 0x608000270200>{number = 3, name = (null)}
2017-05-03 15:13:35.787 test[1168:56601] 1=========<NSThread: 0x608000270200>{number = 3, name = (null)}
2017-05-03 15:13:35.787 test[1168:56601] 2=========<NSThread: 0x608000270200>{number = 3, name = (null)}
2017-05-03 15:13:35.787 test[1168:56601] 2=========<NSThread: 0x608000270200>{number = 3, name = (null)}
2017-05-03 15:13:35.788 test[1168:56601] 3=========<NSThread: 0x608000270200>{number = 3, name = (null)}
2017-05-03 15:13:35.788 test[1168:56601] 3=========<NSThread: 0x608000270200>{number = 3, name = (null)}
  • 開啟了一個新線程陶夜,所有任務(wù)都在該新線程中執(zhí)行
  • 任務(wù)按照順序一個一個執(zhí)行
  • 不會阻塞當(dāng)前線程
  1. 主隊列+同步執(zhí)行
NSLog(@"=============begin") ;
    dispatch_queue_t myQueue = dispatch_get_main_queue() ;
    dispatch_sync(myQueue, ^{
        for(int i = 0; i < 2; i++) {
            NSLog(@"1=========%@",[NSThread currentThread]) ;
        }
    }) ;
    dispatch_sync(myQueue, ^{
        for(int i = 0; i < 2; i++) {
            NSLog(@"2=========%@",[NSThread currentThread]) ;
        }
    }) ;
    dispatch_sync(myQueue, ^{
        for(int i = 0; i < 2; i++) {
            NSLog(@"3=========%@",[NSThread currentThread]) ;
        }
    }) ;
    NSLog(@"=============end") ;

如果在主線程中采用該方式會出現(xiàn)互等卡住的情況凛驮。

在子線程中執(zhí)行的打印結(jié)果為:

2017-05-03 15:34:40.630 test[1279:89558] =============begin
2017-05-03 15:34:40.634 test[1279:89501] 1=========<NSThread: 0x60000006e3c0>{number = 1, name = main}
2017-05-03 15:34:40.635 test[1279:89501] 1=========<NSThread: 0x60000006e3c0>{number = 1, name = main}
2017-05-03 15:34:40.636 test[1279:89501] 2=========<NSThread: 0x60000006e3c0>{number = 1, name = main}
2017-05-03 15:34:40.636 test[1279:89501] 2=========<NSThread: 0x60000006e3c0>{number = 1, name = main}
2017-05-03 15:34:40.636 test[1279:89501] 3=========<NSThread: 0x60000006e3c0>{number = 1, name = main}
2017-05-03 15:34:40.636 test[1279:89501] 3=========<NSThread: 0x60000006e3c0>{number = 1, name = main}
2017-05-03 15:34:40.637 test[1279:89558] =============end
  • 在主線程中執(zhí)行
  • 任務(wù)按照順序一個一個執(zhí)行
  • 會阻塞當(dāng)前線程
  1. 主隊列+異步執(zhí)行
- (void)test {
    NSLog(@"=============begin") ;
    dispatch_queue_t myQueue = dispatch_get_main_queue() ;
    dispatch_async(myQueue, ^{
        for(int i = 0; i < 2; i++) {
            NSLog(@"1=========%@",[NSThread currentThread]) ;
        }
    }) ;
    dispatch_async(myQueue, ^{
        for(int i = 0; i < 2; i++) {
            NSLog(@"2=========%@",[NSThread currentThread]) ;
        }
    }) ;
    dispatch_async(myQueue, ^{
        for(int i = 0; i < 2; i++) {
            NSLog(@"3=========%@",[NSThread currentThread]) ;
        }
    }) ;
    NSLog(@"=============end") ;
}

打印結(jié)果為:

2017-05-03 15:36:10.336 test[1312:93448] =============begin
2017-05-03 15:36:10.337 test[1312:93448] =============end
2017-05-03 15:36:10.347 test[1312:93448] 1=========<NSThread: 0x600000064c80>{number = 1, name = main}
2017-05-03 15:36:10.348 test[1312:93448] 1=========<NSThread: 0x600000064c80>{number = 1, name = main}
2017-05-03 15:36:10.352 test[1312:93448] 2=========<NSThread: 0x600000064c80>{number = 1, name = main}
2017-05-03 15:36:10.358 test[1312:93448] 2=========<NSThread: 0x600000064c80>{number = 1, name = main}
2017-05-03 15:36:10.359 test[1312:93448] 3=========<NSThread: 0x600000064c80>{number = 1, name = main}
2017-05-03 15:36:10.359 test[1312:93448] 3=========<NSThread: 0x600000064c80>{number = 1, name = main}
  • 在主線程中執(zhí)行
  • 任務(wù)按照順序一個一個執(zhí)行
  • 不會阻塞當(dāng)前線程

總結(jié)如下:

隊列 并行隊列 串行隊列 主隊列
同步(sync) 沒有開啟新線程,串行執(zhí)行任務(wù) 沒有開啟新線程条辟,串行執(zhí)行任務(wù) 沒有開啟新線程黔夭,串行執(zhí)行任務(wù)
異步(async) 有開啟新線程,并發(fā)執(zhí)行任務(wù) 有開啟新線程羽嫡,串行執(zhí)行任務(wù) 沒有開啟新線程本姥,串行執(zhí)行任務(wù)

當(dāng)任務(wù)隊列為非主隊列時,只有異步執(zhí)行才會開啟新線程杭棵。如果是并發(fā)隊列,會開啟多條線程婚惫,如果是串行隊列, 只會開啟一條線程。 其他情況下(包括主隊列) 都不會開啟新線程,并且是串行執(zhí)行任務(wù)。

GCD的其他使用

GCD 柵欄函數(shù)

在異步執(zhí)行任務(wù)的過程中辰妙,有時候需要控制任務(wù)執(zhí)行的順序:在第一組任務(wù)執(zhí)行完成后再執(zhí)行第二組任務(wù),可以通過GCD的柵欄函數(shù)dispatch_barrier_async來實現(xiàn)甫窟。當(dāng)柵欄函數(shù)執(zhí)行完成后才會執(zhí)行后面的任務(wù)密浑。

使用

添加?xùn)艡诤瘮?shù)前:

- (void)test {
    NSLog(@"=============begin") ;
    dispatch_queue_t myQueue = dispatch_queue_create("com.appress.myQueue",DISPATCH_QUEUE_CONCURRENT) ;
    dispatch_async(myQueue, ^{
        for(int i = 0; i < 3; i++) {
            NSLog(@"1=========%@",[NSThread currentThread]) ;
        }
    }) ;
    dispatch_async(myQueue, ^{
        for(int i = 0; i < 3; i++) {
            NSLog(@"2=========%@",[NSThread currentThread]) ;
        }
    }) ;
//    dispatch_barrier_async(myQueue, ^{
//        NSLog(@"++++++++++++++++++++++++++++++++++++++++") ;
//    }) ;
    dispatch_async(myQueue, ^{
        for(int i = 0; i < 3; i++) {
            NSLog(@"3=========%@",[NSThread currentThread]) ;
        }
    }) ;
    dispatch_async(myQueue, ^{
        for(int i = 0; i < 3; i++) {
            NSLog(@"4=========%@",[NSThread currentThread]) ;
        }
    }) ;
    NSLog(@"=============end") ;
}

打印結(jié)果為:

2017-05-08 15:37:00.970 test[14150:286911] =============begin
2017-05-08 15:37:00.970 test[14150:286911] =============end
2017-05-08 15:37:00.970 test[14150:286950] 2=========<NSThread: 0x60000026b480>{number = 4, name = (null)}
2017-05-08 15:37:00.970 test[14150:286951] 1=========<NSThread: 0x608000267680>{number = 3, name = (null)}
2017-05-08 15:37:00.970 test[14150:286971] 4=========<NSThread: 0x60000026bac0>{number = 6, name = (null)}
2017-05-08 15:37:00.970 test[14150:286953] 3=========<NSThread: 0x60000026b4c0>{number = 5, name = (null)}
2017-05-08 15:37:00.971 test[14150:286950] 2=========<NSThread: 0x60000026b480>{number = 4, name = (null)}
2017-05-08 15:37:00.971 test[14150:286951] 1=========<NSThread: 0x608000267680>{number = 3, name = (null)}
2017-05-08 15:37:00.971 test[14150:286971] 4=========<NSThread: 0x60000026bac0>{number = 6, name = (null)}
2017-05-08 15:37:00.971 test[14150:286953] 3=========<NSThread: 0x60000026b4c0>{number = 5, name = (null)}
2017-05-08 15:37:00.971 test[14150:286950] 2=========<NSThread: 0x60000026b480>{number = 4, name = (null)}
2017-05-08 15:37:00.971 test[14150:286951] 1=========<NSThread: 0x608000267680>{number = 3, name = (null)}
2017-05-08 15:37:00.972 test[14150:286953] 3=========<NSThread: 0x60000026b4c0>{number = 5, name = (null)}
2017-05-08 15:37:00.972 test[14150:286971] 4=========<NSThread: 0x60000026bac0>{number = 6, name = (null)}

添加?xùn)艡诤瘮?shù)后:

- (void)test {
    NSLog(@"=============begin") ;
    dispatch_queue_t myQueue = dispatch_queue_create("com.appress.myQueue",DISPATCH_QUEUE_CONCURRENT) ;
    dispatch_async(myQueue, ^{
        for(int i = 0; i < 3; i++) {
            NSLog(@"1=========%@",[NSThread currentThread]) ;
        }
    }) ;
    dispatch_async(myQueue, ^{
        for(int i = 0; i < 3; i++) {
            NSLog(@"2=========%@",[NSThread currentThread]) ;
        }
    }) ;
    dispatch_barrier_async(myQueue, ^{
        NSLog(@"++++++++++++++++++++++++++++++++++++++++") ;
    }) ;
    dispatch_async(myQueue, ^{
        for(int i = 0; i < 3; i++) {
            NSLog(@"3=========%@",[NSThread currentThread]) ;
        }
    }) ;
    dispatch_async(myQueue, ^{
        for(int i = 0; i < 3; i++) {
            NSLog(@"4=========%@",[NSThread currentThread]) ;
        }
    }) ;
    NSLog(@"=============end") ;
}

打印結(jié)果為:

2017-05-08 16:02:47.255 test[14241:316852] =============begin
2017-05-08 16:02:47.256 test[14241:316852] =============end
2017-05-08 16:02:47.256 test[14241:316986] 1=========<NSThread: 0x60000006f440>{number = 3, name = (null)}
2017-05-08 16:02:47.256 test[14241:316983] 2=========<NSThread: 0x60800006c2c0>{number = 4, name = (null)}
2017-05-08 16:02:47.256 test[14241:316986] 1=========<NSThread: 0x60000006f440>{number = 3, name = (null)}
2017-05-08 16:02:47.256 test[14241:316983] 2=========<NSThread: 0x60800006c2c0>{number = 4, name = (null)}
2017-05-08 16:02:47.256 test[14241:316986] 1=========<NSThread: 0x60000006f440>{number = 3, name = (null)}
2017-05-08 16:02:47.257 test[14241:316983] 2=========<NSThread: 0x60800006c2c0>{number = 4, name = (null)}
2017-05-08 16:02:47.257 test[14241:316983] ++++++++++++++++++++++++++++++++++++++++
2017-05-08 16:02:47.257 test[14241:316983] 3=========<NSThread: 0x60800006c2c0>{number = 4, name = (null)}
2017-05-08 16:02:47.257 test[14241:316986] 4=========<NSThread: 0x60000006f440>{number = 3, name = (null)}
2017-05-08 16:02:47.257 test[14241:316983] 3=========<NSThread: 0x60800006c2c0>{number = 4, name = (null)}
2017-05-08 16:02:47.257 test[14241:316986] 4=========<NSThread: 0x60000006f440>{number = 3, name = (null)}
2017-05-08 16:02:47.257 test[14241:316983] 3=========<NSThread: 0x60800006c2c0>{number = 4, name = (null)}
2017-05-08 16:02:47.258 test[14241:316986] 4=========<NSThread: 0x60000006f440>{number = 3, name = (null)}

注意

  • 柵欄函數(shù)不能使用全局的并發(fā)隊列。

GCD的迭代

使用

dispatch_apply(迭代次數(shù), 線程隊列(并發(fā)隊列), ^(size_t index索引) {
       執(zhí)行任務(wù) ;
}) ;

注意

  • 開啟了子線程來執(zhí)行任務(wù)
  • 迭代不是按照順序的

GCD隊列組

異步執(zhí)行多個耗時操作粗井,當(dāng)所有操作都執(zhí)行完畢后再執(zhí)行某一操作尔破。可以通過使用GCD隊列組來實現(xiàn)浇衬。

使用

NSLog(@"===============begin") ;
dispatch_group_t group = dispatch_group_create() ;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) ;
dispatch_group_async(group, queue, ^{
    for(int i = 0 ; i < 4 ; i ++) {
        NSLog(@"1===============%@",[NSThread currentThread]) ;
    }
}) ;
dispatch_group_async(group, queue, ^{
    for(int i = 0 ; i < 4 ; i ++) {
        NSLog(@"2===============%@",[NSThread currentThread]) ;
    }
}) ;
dispatch_group_async(group, queue, ^{
    for(int i = 0 ; i < 4 ; i ++) {
        NSLog(@"3===============%@",[NSThread currentThread]) ;
    }
}) ;
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    NSLog(@"===============end") ;
}) ;

打印結(jié)果為:

2017-08-08 13:36:21.124 GCD[3643:200121] ===============begin
2017-08-08 13:36:21.125 GCD[3643:200159] 1===============<NSThread: 0x60000007f2c0>{number = 3, name = (null)}
2017-08-08 13:36:21.125 GCD[3643:200156] 3===============<NSThread: 0x608000267100>{number = 5, name = (null)}
2017-08-08 13:36:21.125 GCD[3643:200157] 2===============<NSThread: 0x60800007cac0>{number = 4, name = (null)}
2017-08-08 13:36:21.125 GCD[3643:200159] 1===============<NSThread: 0x60000007f2c0>{number = 3, name = (null)}
2017-08-08 13:36:21.125 GCD[3643:200156] 3===============<NSThread: 0x608000267100>{number = 5, name = (null)}
2017-08-08 13:36:21.125 GCD[3643:200157] 2===============<NSThread: 0x60800007cac0>{number = 4, name = (null)}
2017-08-08 13:36:21.125 GCD[3643:200159] 1===============<NSThread: 0x60000007f2c0>{number = 3, name = (null)}
2017-08-08 13:36:21.125 GCD[3643:200156] 3===============<NSThread: 0x608000267100>{number = 5, name = (null)}
2017-08-08 13:36:21.126 GCD[3643:200157] 2===============<NSThread: 0x60800007cac0>{number = 4, name = (null)}
2017-08-08 13:36:21.126 GCD[3643:200159] 1===============<NSThread: 0x60000007f2c0>{number = 3, name = (null)}
2017-08-08 13:36:21.126 GCD[3643:200156] 3===============<NSThread: 0x608000267100>{number = 5, name = (null)}
2017-08-08 13:36:21.126 GCD[3643:200157] 2===============<NSThread: 0x60800007cac0>{number = 4, name = (null)}
2017-08-08 13:36:21.132 GCD[3643:200121] ===============end

如果dispatch_group_async的操作中有延時回調(diào)懒构,那么在所有回調(diào)完成前就會執(zhí)行dispatch_group_notify

typedef void (^resultBlock) () ;
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"===============begin") ;
    dispatch_group_t group = dispatch_group_create() ;
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) ;
    dispatch_group_async(group, queue, ^{
        [self testWithBlock:^{
            for(int i = 0 ; i < 4 ; i ++) {
                NSLog(@"1===============%@",[NSThread currentThread]) ;
            }
        }] ;
    }) ;
    dispatch_group_async(group, queue, ^{
        [self testWithBlock:^{
            for(int i = 0 ; i < 4 ; i ++) {
                NSLog(@"2===============%@",[NSThread currentThread]) ;
            }
        }] ;

    }) ;
    dispatch_group_async(group, queue, ^{
        [self testWithBlock:^{
            for(int i = 0 ; i < 4 ; i ++) {
                NSLog(@"3===============%@",[NSThread currentThread]) ;
            }
        }] ;
    }) ;
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"===============end") ;
    }) ;
}

- (void)testWithBlock:(resultBlock)block {
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0*NSEC_PER_SEC)) ;
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT) ;
    dispatch_after(time, queue, ^{
        block() ;
    }) ;
}

打印結(jié)果為:

2017-08-08 14:40:25.811 GCD[16467:291922] ===============begin
2017-08-08 14:40:26.048 GCD[16467:291922] ===============end
2017-08-08 14:40:28.007 GCD[16467:291980] 1===============<NSThread: 0x60000007c900>{number = 3, name = (null)}
2017-08-08 14:40:28.007 GCD[16467:291979] 3===============<NSThread: 0x608000262100>{number = 4, name = (null)}
2017-08-08 14:40:28.007 GCD[16467:291982] 2===============<NSThread: 0x60000007c340>{number = 5, name = (null)}
2017-08-08 14:40:28.008 GCD[16467:291979] 3===============<NSThread: 0x608000262100>{number = 4, name = (null)}
2017-08-08 14:40:28.008 GCD[16467:291980] 1===============<NSThread: 0x60000007c900>{number = 3, name = (null)}
2017-08-08 14:40:28.008 GCD[16467:291982] 2===============<NSThread: 0x60000007c340>{number = 5, name = (null)}
2017-08-08 14:40:28.008 GCD[16467:291979] 3===============<NSThread: 0x608000262100>{number = 4, name = (null)}
2017-08-08 14:40:28.008 GCD[16467:291980] 1===============<NSThread: 0x60000007c900>{number = 3, name = (null)}
2017-08-08 14:40:28.008 GCD[16467:291982] 2===============<NSThread: 0x60000007c340>{number = 5, name = (null)}
2017-08-08 14:40:28.009 GCD[16467:291979] 3===============<NSThread: 0x608000262100>{number = 4, name = (null)}
2017-08-08 14:40:28.009 GCD[16467:291980] 1===============<NSThread: 0x60000007c900>{number = 3, name = (null)}
2017-08-08 14:40:28.009 GCD[16467:291982] 2===============<NSThread: 0x60000007c340>{number = 5, name = (null)}

通過dispatch_group_enter(group)dispatch_group_leave(group)的配合使用來解決這個問題耘擂。

typedef void (^resultBlock) () ;

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"===============begin") ;
    dispatch_group_t group = dispatch_group_create() ;
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) ;
    dispatch_group_enter(group) ;
    dispatch_group_async(group, queue, ^{
        [self testWithBlock:^{
            for(int i = 0 ; i < 4 ; i ++) {
                NSLog(@"1===============%@",[NSThread currentThread]) ;
            }
            dispatch_group_leave(group) ;
        }] ;
    }) ;
    dispatch_group_enter(group) ;
    dispatch_group_async(group, queue, ^{
        [self testWithBlock:^{
            for(int i = 0 ; i < 4 ; i ++) {
                NSLog(@"2===============%@",[NSThread currentThread]) ;
            }
            dispatch_group_leave(group) ;
        }] ;

    }) ;
    dispatch_group_enter(group) ;
    dispatch_group_async(group, queue, ^{
        [self testWithBlock:^{
            for(int i = 0 ; i < 4 ; i ++) {
                NSLog(@"3===============%@",[NSThread currentThread]) ;
            }
            dispatch_group_leave(group) ;
        }] ;
    }) ;
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"===============end") ;
    }) ;
}

- (void)testWithBlock:(resultBlock)block {
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0*NSEC_PER_SEC)) ;
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT) ;
    dispatch_after(time, queue, ^{
        block() ;
    }) ;
}

@end

打印結(jié)果為:

2017-08-08 15:03:07.867 GCD[16548:311040] ===============begin
2017-08-08 15:03:09.868 GCD[16548:311101] 2===============<NSThread: 0x6000000773c0>{number = 5, name = (null)}
2017-08-08 15:03:09.868 GCD[16548:311098] 3===============<NSThread: 0x60000007ab40>{number = 3, name = (null)}
2017-08-08 15:03:09.868 GCD[16548:311099] 1===============<NSThread: 0x608000071d80>{number = 4, name = (null)}
2017-08-08 15:03:09.869 GCD[16548:311101] 2===============<NSThread: 0x6000000773c0>{number = 5, name = (null)}
2017-08-08 15:03:09.869 GCD[16548:311098] 3===============<NSThread: 0x60000007ab40>{number = 3, name = (null)}
2017-08-08 15:03:09.869 GCD[16548:311099] 1===============<NSThread: 0x608000071d80>{number = 4, name = (null)}
2017-08-08 15:03:09.869 GCD[16548:311101] 2===============<NSThread: 0x6000000773c0>{number = 5, name = (null)}
2017-08-08 15:03:09.869 GCD[16548:311098] 3===============<NSThread: 0x60000007ab40>{number = 3, name = (null)}
2017-08-08 15:03:09.869 GCD[16548:311099] 1===============<NSThread: 0x608000071d80>{number = 4, name = (null)}
2017-08-08 15:03:09.869 GCD[16548:311101] 2===============<NSThread: 0x6000000773c0>{number = 5, name = (null)}
2017-08-08 15:03:09.870 GCD[16548:311098] 3===============<NSThread: 0x60000007ab40>{number = 3, name = (null)}
2017-08-08 15:03:09.870 GCD[16548:311099] 1===============<NSThread: 0x608000071d80>{number = 4, name = (null)}
2017-08-08 15:03:09.870 GCD[16548:311040] ===============end

通過這種方法可以解決諸如:多個網(wǎng)絡(luò)請求全部完成以后再進(jìn)行某項操作的問題胆剧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市醉冤,隨后出現(xiàn)的幾起案子秩霍,更是在濱河造成了極大的恐慌,老刑警劉巖蚁阳,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铃绒,死亡現(xiàn)場離奇詭異,居然都是意外死亡螺捐,警方通過查閱死者的電腦和手機(jī)颠悬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來定血,“玉大人赔癌,你說我怎么就攤上這事±焦担” “怎么了届榄?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長倔喂。 經(jīng)常有香客問我铝条,道長,這世上最難降的妖魔是什么席噩? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任班缰,我火速辦了婚禮,結(jié)果婚禮上悼枢,老公的妹妹穿的比我還像新娘埠忘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布莹妒。 她就那樣靜靜地躺著名船,像睡著了一般。 火紅的嫁衣襯著肌膚如雪旨怠。 梳的紋絲不亂的頭發(fā)上渠驼,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機(jī)與錄音鉴腻,去河邊找鬼迷扇。 笑死,一個胖子當(dāng)著我的面吹牛爽哎,可吹牛的內(nèi)容都是我干的蜓席。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼课锌,長吁一口氣:“原來是場噩夢啊……” “哼厨内!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起渺贤,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤隘庄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后癣亚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體丑掺,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年述雾,在試婚紗的時候發(fā)現(xiàn)自己被綠了街州。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡玻孟,死狀恐怖唆缴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情黍翎,我是刑警寧澤面徽,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站匣掸,受9級特大地震影響趟紊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜碰酝,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一霎匈、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧送爸,春花似錦铛嘱、人聲如沸暖释。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽球匕。三九已至,卻和暖如春帖烘,著一層夾襖步出監(jiān)牢的瞬間亮曹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工蚓让, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人讥珍。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓历极,卻偏偏與公主長得像,于是被迫代替她去往敵國和親衷佃。 傳聞我的和親對象是個殘疾皇子趟卸,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,446評論 2 348

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