美文网首页
iOS多线程---GCD

iOS多线程---GCD

作者: iOS程序媛ing | 来源:发表于2020-09-07 16:33 被阅读0次

    本文主要介绍GCD的基本概念,使用方法。

    死锁

    • 只要在同一队列中,同步任务套同步任务,一定会死锁,重点是《同一队列》
    • 如果在主线程中,创建一个同步队列,并在住队列中添加一个同步任务,是不会造成主线程死锁的,因为不是同一个队列。但是此同步任务是在主线程执行的,因为同步任务不具备开辟线程能力。

    1、GCD任务和队列

    学习GCD,首先要了解任务和队列两个概念。

    1 .1任务:执行操作的意思。任务分为同步任务和异步任务,区别在于:是否需要等待队列里的任务执行完毕之后再去执行,是否具备开辟线程的能力。

    同步任务

    (1)同步添加任务到队列中,在添加的任务执行完之前,会一直等待,直到队列里的任务执行完之后才会继续执行。

    (2)不具备开辟线程能力。

    异步任务:

    (1)异步添加任务到队列,不做任何等待,继续执行任务。

    (2)具备开辟线程能力。

    1.2队列,分为串行队列和并发队列。这里的队列指等待执行任务的队列,队列采用先进先出原则,先添加的任务先执行。

    串行队列:每次只执行一个任务,任务一个一个,按顺序执行,(只开启一条线程)

    并发队列:任务同时执行,不需要等待,可以开启多条线程

    2、GCD 的使用

    1、首先创建线程(串行队列、并行队列)。

    2、创建任务添加到线程中。

    1.1创建线程

    
    dispatch_queue_create(<#const char * _Nullable label#>, <#dispatch_queue_attr_t  _Nullable attr#>)
    
    

    (1)第一个参数是队列的唯一标识符;
    (2)第二个参数表示是串行队列还是并行队列
    DISPATCH_QUEUE_CONCURRENT代表并行队列
    DISPATCH_QUEUE_SERIAL代表并行队列

    创建并行队列
    dispatch_queue_t concurrentQueue = dispatch_queue_create("1", DISPATCH_QUEUE_CONCURRENT);
    创建串行队列
    dispatch_queue_t serialqueue = dispatch_queue_create("2", DISPATCH_QUEUE_SERIAL);
    

    1.2串行队列,系统提供默认的串行队列---主队列 ,通过

    dispatch_get_main_queue()
    

    获取主队列
    1.3并行队列,系统默认提供了全局并发队列,可以通过如下方法获取全局并发队列,第一个参数代表队列的优先级,

    dispatch_get_global_queue(<#long identifier#>, <#unsigned long flags#>)
    
    // 全局并发队列的获取方法
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    

    2、创建任务

    创建同步任务
    dispatch_sync(<#dispatch_queue_t  _Nonnull queue#>, <#^(void)block#>)
    创建异步任务
    dispatch_async(<#dispatch_queue_t  _Nonnull queue#>, <#^(void)block#>)
    

    两种任务和两种队列的组合共有四种,分别为
    1、同步任务+串行队列
    2、同步任务+并行队列
    3、异步任务+串行队列
    4、异步任务+并行队列
    在加上主队列
    5、同步任务+主队列
    6、异步任务+主队列

    区别 串行队列 并行队列 主队列
    同步任务 不开辟线程串行执行 不开辟线程,串行执行任务 死锁卡住,不执行
    异步任务 开辟一条线程 开辟线程,并发执行任务 不开辟线程,串行执行

    实际开发过程中可能还会遇到任务套任务,队列套队列,我们只需要记住,只要是在同一串行队列中,无论是同步任务还是异步任务,只要套同步任务,必定死锁。

    3、GCD队列组---dispatch_group_t

    项目中可能有请求完所有数据后,再刷新界面的情况,这种情况,我们可以使用队列组。

    创建队列组
    dispatch_group_t group = dispatch_group_create();
    
     创建队列
     dispatch_queue_t concurrentQueue = dispatch_queue_create("1", DISPATCH_QUEUE_CONCURRENT);
    
        添加任务到队列组,第一个参数为队列组,第二个参数为队列
        dispatch_group_async(group, concurrentQueue, ^{
            开始任务
           dispatch_group_enter(group);
            NSLog(@"任务一");
            任务结束
            dispatch_group_leave(group)
        });
        dispatch_group_async(group, concurrentQueue, ^{
           dispatch_group_enter(group);
            NSLog(@"任务一");
            dispatch_group_leave(group)
        });
    

    最后调用dispatch_group_notify方法回到指定线程,执行操作

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"回到主线程刷新界面");
        });
    

    4、栅栏dispatch_barrier

    如果当前需要执行完两个操作后再去执行另外两个操作,我们可以使用栅栏实现。
    (1)dispatch_barrier_sync. 执行完栅栏前面的操作后,先执行栅栏里的操作,再执行栅栏后的操作,会阻塞当前线程。

    dispatch_queue_t queue = dispatch_queue_create("1", DISPATCH_QUEUE_CONCURRENT);
        NSLog(@"=======");
        dispatch_async(queue, ^{
            sleep(1);
            NSLog(@"1--栅栏前操作");
        });
        dispatch_async(queue, ^{
            sleep(2);
            NSLog(@"2--栅栏前操作");
        });
        dispatch_barrier_sync(queue, ^{
            NSLog(@"栅栏中的操作");
        });
        sleep(3);
        NSLog(@"栅栏后的操作");
        dispatch_async(queue, ^{
            NSLog(@"3--栅栏后操作");
        });
        dispatch_async(queue, ^{
            NSLog(@"4--栅栏后操作");
        });
    

    打印结果如下

    2020-09-08 09:16:43.151241+0800 面试[18493:1620903] =======
    2020-09-08 09:16:44.152391+0800 面试[18493:1621063] 1--栅栏前操作
    2020-09-08 09:16:45.153717+0800 面试[18493:1621060] 2--栅栏前操作
    2020-09-08 09:16:45.154062+0800 面试[18493:1620903] 栅栏中的操作
    2020-09-08 09:16:48.155522+0800 面试[18493:1620903] 栅栏后的操作
    2020-09-08 09:16:48.155899+0800 面试[18493:1621060] 3--栅栏后操作
    2020-09-08 09:16:48.155928+0800 面试[18493:1621063] 4--栅栏后操作
    
    
    

    (2)dispatch_barrier_async 执行完栅栏前面的操作后,先执行栅栏后不在一个队列方法

    dispatch_queue_t queue = dispatch_queue_create("1", DISPATCH_QUEUE_CONCURRENT);
        NSLog(@"=======");
        dispatch_async(queue, ^{
            sleep(1);
            NSLog(@"1--栅栏前操作");
        });
        dispatch_async(queue, ^{
            sleep(2);
            NSLog(@"2--栅栏前操作");
        });
        dispatch_barrier_async(queue, ^{
            NSLog(@"栅栏中的操作");
        });
        sleep(3);
        NSLog(@"栅栏后的操作");
        dispatch_async(queue, ^{
            NSLog(@"3--栅栏后操作");
        });
        dispatch_async(queue, ^{
            NSLog(@"4--栅栏后操作");
        });
        
    

    打印结果如下

    2020-09-08 09:10:58.345846+0800 面试[18469:1616956] =======
    2020-09-08 09:10:59.350198+0800 面试[18469:1617006] 1--栅栏前操作
    2020-09-08 09:11:00.349971+0800 面试[18469:1617009] 2--栅栏前操作
    2020-09-08 09:11:00.350303+0800 面试[18469:1617009] 栅栏中的操作
    2020-09-08 09:11:01.346548+0800 面试[18469:1616956] 栅栏后的操作
    2020-09-08 09:11:01.346878+0800 面试[18469:1617009] 3--栅栏后操作
    2020-09-08 09:11:01.346894+0800 面试[18469:1617008] 4--栅栏后操作
    
    

    相关文章

      网友评论

          本文标题:iOS多线程---GCD

          本文链接:https://www.haomeiwen.com/subject/tzqlektx.html