GCD多线程应用

概念

在GCD中有两个重要的概念:任务和队列。

任务

所要执行的操作。任务有两种执行方式:同步执行和异步执行。

  • 同步执行:
    1. 会阻塞当前线程,直到任务执行完成才会返回当前线程继续运行
    2. 不具备开启新线程的能力
  • 异步执行:
    1. 不会阻塞当前线程,会立即返回当前线程继续运行
    2. 具备开启新线程的能力

队列

用于存放任务。队列有两种:串行队列和并发队列。

  • 串行队列:

    1. 任务执行遵循先进先出的顺序,下一个任务在上一个任务执行完成后开始执行
    2. 创建方式(两种)
    dispatch_queue_t serialQueue = dispatch_queue_create("com.apress.mySerialQueue", nil) ;
    dispatch_queue_t serialQueue = dispatch_queue_create("com.apress.mySerialQueue", DISPATCH_QUEUE_SERIAL) ;
    
  • 并发队列:

    1. 任务执行遵循先进先出的顺序,下一个任务可以在上一个任务执行完成前开始执行
    2. 创建方式
    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.appress.myConcurrentQueue",DISPATCH_QUEUE_CONCURRENT) ;
    
    1. 系统提供了四种全局的并发队列,这些队列通过优先级加以区别。高优先级队列中的任务会比在默认或低优先级队列中的任务先执行,而默认级别队列的优先级又高于低优先级队列。被设置成后台级别的队列,它会等待所有比它级别高的队列中的任务执行完或CPU空闲的时候才会执行自己的任务
    dispatch_queue_t  concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) ;
    
    字段 优先级
    DISPATCH_QUEUE_PRIORITY_HIGH 高优先级
    DISPATCH_QUEUE_PRIORITY_DEFAULT 默认优先级
    DISPATCH_QUEUE_PRIORITY_LOW 低优先级
    DISPATCH_QUEUE_PRIORITY_BACKGROUND 后台级别
  • 主队列:
    除了串行队列和并发队列,还有一种特殊的队列——主队列。

    1. 是串行队列
    2. 所有放在主队列中的任务都会放到主线程中执行
    3. 可通过dispatch_get_main_queue()获得

GCD的多线程使用

使用步骤

  1. 创建队列
  2. 向队列中添加任务:
    • 通过dispatch_async进行异步添加
    • 通过dispatch_sync进行同步添加

使用方式

由于存在不同的队列和任务执行方式,因此有多种组合方式来使用。

  1. 并发队列+同步执行
- (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") ;
}

打印结果为:

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
  • 不会开启新线程,而是在当前线程执行
  • 任务按照顺序一个一个执行
  • 会阻塞当前线程
  1. 并发队列+异步执行
- (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") ;
}

打印结果为:

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)}
  • 开启了多个新线程,并且在各自的新线程中执行
  • 任务交替着同时执行
  • 不会阻塞当前线程
  1. 串行队列+同步执行
- (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") ;
}

打印结果为:

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
  • 不会开启新线程,而是在当前线程执行
  • 任务按照顺序一个一个执行
  • 会阻塞当前线程
  1. 串行队列+异步执行
- (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") ;
}

打印结果为:

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)}
  • 开启了一个新线程,所有任务都在该新线程中执行
  • 任务按照顺序一个一个执行
  • 不会阻塞当前线程
  1. 主队列+同步执行
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") ;

如果在主线程中采用该方式会出现互等卡住的情况。

在子线程中执行的打印结果为:

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
  • 在主线程中执行
  • 任务按照顺序一个一个执行
  • 会阻塞当前线程
  1. 主队列+异步执行
- (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") ;
}

打印结果为:

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}
  • 在主线程中执行
  • 任务按照顺序一个一个执行
  • 不会阻塞当前线程

总结如下:

队列 并行队列 串行队列 主队列
同步(sync) 没有开启新线程,串行执行任务 没有开启新线程,串行执行任务 没有开启新线程,串行执行任务
异步(async) 有开启新线程,并发执行任务 有开启新线程,串行执行任务 没有开启新线程,串行执行任务

当任务队列为非主队列时,只有异步执行才会开启新线程。如果是并发队列,会开启多条线程,如果是串行队列, 只会开启一条线程。 其他情况下(包括主队列) 都不会开启新线程,并且是串行执行任务。

GCD的其他使用

GCD 栅栏函数

在异步执行任务的过程中,有时候需要控制任务执行的顺序:在第一组任务执行完成后再执行第二组任务,可以通过GCD的栅栏函数dispatch_barrier_async来实现。当栅栏函数执行完成后才会执行后面的任务。

使用

添加栅栏函数前:

- (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") ;
}

打印结果为:

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)}

添加栅栏函数后:

- (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") ;
}

打印结果为:

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)}

注意

  • 栅栏函数不能使用全局的并发队列。

GCD的迭代

使用

dispatch_apply(迭代次数, 线程队列(并发队列), ^(size_t index索引) {
       执行任务 ;
}) ;

注意

  • 开启了子线程来执行任务
  • 迭代不是按照顺序的

GCD队列组

异步执行多个耗时操作,当所有操作都执行完毕后再执行某一操作。可以通过使用GCD队列组来实现。

使用

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") ;
}) ;

打印结果为:

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的操作中有延时回调,那么在所有回调完成前就会执行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() ;
    }) ;
}

打印结果为:

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

打印结果为:

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

通过这种方法可以解决诸如:多个网络请求全部完成以后再进行某项操作的问题。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容