GCD队列使用

使用GCD前,先对队列总结一下:

串行和并发

GCD中队列分为两种:串行队列、并发队列。
串行队列:任务按在队列里的先后顺序执行,先进先出(FIFO),一个任务执行完成后,才会执行下一个任务(实际实现是在一个线程中完成所有任务,这个线程可能是主线程,也可能是子线程)。
并发队列:任务无序同时执行(实际实现是在多个子线程中执行)。

同步和异步

任务的执行方式分为同步和异步两种,同步和异步是以是否在当前线程执行区分的。
同步执行:任务都在当前线程中执行,并且会阻塞当前线程。
异步执行:任务会开辟新的线程,并在新的线程中执行,不会阻塞当前线程。

组合四种队列

两种队列和两种执行方式组合起来就形成了四种队列:串行同步队列、串行异步队列、并发同步队列、并发异步队列。四种队列区别如下(先贴结论,后面验证):

串行同步队列:任务都在当前线程执行(同步),并且顺序执行(串行)
串行异步队列:任务都在开辟的新的子线程中执行(异步),并且顺序执行(串行)
并发同步队列:任务都在当前线程执行(同步),但是是顺序执行的(并发的特性并没有体现出来)
并发异步队列:任务在开辟的多个子线程中执行(异步),并且是同时执行的(并发)

注:由上面的特性即可看出,我们平时对GCD使用最多的是并发异步队列。

准备工作

研究队列类型之间的区别前,先看一下GCD中生成队列的方法:
方法一:dispatch_queue_create:可以生成串行和并发队列

// 前两个方法生成的是串行队列;第三个生成的是并发队列
dispatch_queue_create("com.serial.queue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_create("com.serial.queue", NULL);
dispatch_queue_create("com.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);

方法二:dispatch_get_global_queue:只能生成并发队列

// 只能生成并发队列
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

验证四种队列

打印方法:

#pragma mark - private methods
- (void)p_printThread:(int)index {
    NSLog(@"%@-------%d", [NSThread currentThread], index);
}

1.串行同步队列

dispatch_queue_t queue = dispatch_queue_create("com.serial.queue", NULL);
    dispatch_sync(queue, ^(){
        [self p_printThread:1];
    });
    dispatch_sync(queue, ^(){
        [self p_printThread:2];
    });
    dispatch_sync(queue, ^(){
        [self p_printThread:3];
    });
    dispatch_sync(queue, ^(){
        [self p_printThread:4];
    });

打印结果:

{number = 1, name = main}-------1
{number = 1, name = main}-------2
{number = 1, name = main}-------3
{number = 1, name = main}-------4

结论:在串行同步队列中,任务都在当前线程执行(同步),并且顺序执行(串行)。
注:打印的结果都是主线程,是因为当前线程是主线程,这并不是说同步就是在主线程执行的。

2.串行异步队列

dispatch_queue_t queue = dispatch_queue_create("com.serial.queue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^(){
        [self p_printThread:1];
    });
    dispatch_async(queue, ^(){
        [self p_printThread:2];
    });
    dispatch_async(queue, ^(){
        [self p_printThread:3];
    });
    dispatch_async(queue, ^(){
        [self p_printThread:4];
    });

打印结果:

 {number = 3, name = (null)}-------1
 {number = 3, name = (null)}-------2
 {number = 3, name = (null)}-------3
 {number = 3, name = (null)}-------4

结论:在串行异步队列中,任务都在新开辟的子线程中执行(异步),并且顺序执行(串行)。

3.并发同步队列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_sync(queue, ^(){
        [self p_printThread:1];
    });
    dispatch_sync(queue, ^(){
        [self p_printThread:2];
    });
    dispatch_sync(queue, ^(){
        [self p_printThread:3];
    });
    dispatch_sync(queue, ^(){
        [self p_printThread:4];
    });

打印结果:

 {number = 1, name = main}-------1
 {number = 1, name = main}-------2
 {number = 1, name = main}-------3
 {number = 1, name = main}-------4

结论:在并发同步队列中,任务都在当前线程中执行(同步),但是是顺序执行的(并发的特性并没有体现出来,因为同步会阻塞当前线程)。

4.并发异步队列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^(){
        [self p_printThread:1];
    });
    dispatch_async(queue, ^(){
        [self p_printThread:2];
    });
    dispatch_async(queue, ^(){
        [self p_printThread:3];
    });
    dispatch_async(queue, ^(){
        [self p_printThread:4];
    });

打印结果:

 {number = 4, name = (null)}-------2
 {number = 6, name = (null)}-------4
 {number = 3, name = (null)}-------1
 {number = 5, name = (null)}-------3

结论:在并发异步队列中,任务在多个新开辟的子线程中执行(异步),并且是同时无序地执行的(并发)

分析总结

由上面代码示例可以看出,串行队列就是在一个线程执行的队列:如果是当前线程,那就是串行同步队列(因为同步机制会阻塞当前线程),如果是新开辟的子线程,就是串行异步队列;并发队列如果是在当前线程中执行,就是并发同步队列,在新开辟的多个子线程中执行就是并发异步队列。
综上所述,我们平时使用最多的自然是并发异步队列,比如开辟多个子线程下载图片、文件等。

你可能感兴趣的:(GCD队列使用)