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