iOS多线程---GCD

2020-09-07  本文已影响0人  iOS程序媛ing

本文主要介绍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--栅栏后操作

上一篇下一篇

猜你喜欢

热点阅读