免费开源的iOS开发学习平台

GCD使用介绍:2-队列与任务的组合

在GCD中存在队列和任务两个核心概念,同时队列又分为并行队列、串行队列和主队列,任务包括异步任务和同步任务。GCD的使用方法就是把任务放到队列中执行,因而根据不同的任务类型和队列类型,就会存在6种组合。

1、异步任务+并行队列

把异步任务放到并行队列进行执行,异步任务会在不同的线程中执行,这是最常使用的一种组合。

    //获取并行队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);    
    //创建异步任务,并放到并行队列中执行
    dispatch_async(queue, ^{
        for (int i = 0; i<2; i++) {
            NSLog(@"task1:%d",i);
        }
        NSLog(@"task1----%@",[NSThread currentThread]);
    });    
    dispatch_async(queue, ^{
        for (int i = 0; i<2; i++) {
            NSLog(@"task2:%d",i);
        }
        NSLog(@"task2----%@",[NSThread currentThread]);
    });  
    dispatch_async(queue, ^{
        for (int i = 0; i<2; i++) {
            NSLog(@"task3:%d",i);
        }
        NSLog(@"task3----%@",[NSThread currentThread]);
    });   

运行结果如下。异步任务+并行队列组合情况下,每个任务会在不同的线程中同时执行。

2、异步任务+串行队列

对于异步任务放在串行队列中执行时,任务只会在一个新开的线程中,按照顺序进行执行。

    //创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("com.99ios", NULL); 
    //创建异步任务
    dispatch_async(queue, ^{
        for (int i = 0; i<2; i++) {
            NSLog(@"task1:%d",i);
        }
        NSLog(@"task1----%@",[NSThread currentThread]);
    });  
    dispatch_async(queue, ^{
        for (int i = 0; i<2; i++) {
            NSLog(@"task2:%d",i);
        }
        NSLog(@"task2----%@",[NSThread currentThread]);
    });   
    dispatch_async(queue, ^{
        for (int i = 0; i<2; i++) {
            NSLog(@"task3:%d",i);
        }
        NSLog(@"task3----%@",[NSThread currentThread]);
    });

运行结果如下。可以看到,所有任务都在一个线程中执行,并且完成一个后,再执行下一个。

3、异步任务+主队列

把异步任务放在主队列中执行,由于主队列是一个特殊的串行队列,因此任务是串行执行的,但由于主队列对应序号为1的线程,因此,即便是异步任务,也不会再创建新的线程。

    //获取主队列
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    //创建异步任务
    dispatch_async(mainQueue, ^{
        for (int i = 0; i<2; i++) {
            NSLog(@"task1:%d",i);
        }
        NSLog(@"task1----%@",[NSThread currentThread]);
    });
    dispatch_async(mainQueue, ^{
        for (int i = 0; i<2; i++) {
            NSLog(@"task2:%d",i);
        }
        NSLog(@"task2----%@",[NSThread currentThread]);
    });
    dispatch_async(mainQueue, ^{
        for (int i = 0; i<2; i++) {
            NSLog(@"task3:%d",i);
        }
        NSLog(@"task3----%@",[NSThread currentThread]);
    });

运行结果如下:

4、同步任务+并行队列

同步任务的执行是在当前线程中完成的,因此,即便是把同步任务放在并行队列中执行,由于只有1个线程,任务也是一个一个按顺序执行的(串行执行)。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //获取并行队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //同步执行
    dispatch_sync(queue, ^{
        for (int i = 0; i<2; i++) {
            NSLog(@"task1:%d",i);
        }
        NSLog(@"task1----%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i<2; i++) {
            NSLog(@"task2:%d",i);
        }
        NSLog(@"task2----%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i<2; i++) {
            NSLog(@"task3:%d",i);
        }
        NSLog(@"task3----%@",[NSThread currentThread]);
    });

}

运行结果如下,由于viewDidLoad方法是在主线程中执行的,因此,创建的同步任务也在主线程中执行。

5、同步任务+串行队列

同步任务放在串行队列中执行,任务会在当前线程依次执行。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("com.99ios", NULL);
    //同步执行
    dispatch_sync(queue, ^{
        for (int i = 0; i<2; i++) {
            NSLog(@"task1:%d",i);
        }
        NSLog(@"task1----%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i<2; i++) {
            NSLog(@"task2:%d",i);
        }
        NSLog(@"task2----%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i<2; i++) {
            NSLog(@"task3:%d",i);
        }
        NSLog(@"task3----%@",[NSThread currentThread]);
    });

}

运行结果如下,由于viewDidLoad方法是在主线程中执行的,因此,创建的同步任务也在主线程中执行。

6、同步任务+主队列

这种情况下,主线程会被阻塞,程序会挂死,不能使用!

    //获取主队列
    dispatch_queue_t mainQueue = dispatch_get_main_queue(); 
    //同步执行
    //1
    dispatch_sync(mainQueue, ^{ //block 1
        for (int i = 0; i<2; i++) {
            NSLog(@"task1:%d",i);
        }
        NSLog(@"task1----%@",[NSThread currentThread]);
    });
    //2
    dispatch_sync(mainQueue, ^{
        for (int i = 0; i<2; i++) {
            NSLog(@"task2:%d",i);
        }
        NSLog(@"task2----%@",[NSThread currentThread]);
    });
    //3
    dispatch_sync(mainQueue, ^{ 
        for (int i = 0; i<2; i++) {
            NSLog(@"task3:%d",i);
        }
        NSLog(@"task3----%@",[NSThread currentThread]);
    });

当调用dispatch_sync会阻塞线程,直到任务(block)执行完成之后才能继续执行。主线程中初始时需要执行的代码如下所示。主线程需要执行1,2,3三块代码。

执行完1之后主线程需要执行的代码如下所示。将任务(block)添加到主线程中去执行。同时阻塞主线程,直到任务(block)执行完成。此时block 1等待3的代码执行完成,而代码1需要等block 1执行完成。这就造成了1block 1相互等待,成了死锁。

示例代码

https://github.com/99ios/11.2.2