Grand Central Dispatch 简称(GCD)。GCD完全可以处理诸如 数据锁定和资源泄漏等复杂的异步编程问题。
GCD的底层依然是用线程实现,不过这样可以让程序员不用关注实现的细节。
GCD中的FIFO(先进先出)队列称为dispatch queue,它可以保证先进来的任务先得到执行
dispatch queue分为三种:
1.Serial Queue 串行队列
2,Concurrent Queue 并行队列
3,Main dispatch queue 主队列
有4个术语比较容易混淆:同步、异步、并发、串行
1,同步和异步决定了要不要开启新的线程
同步:在当前线程中执行任务,不具备开启新线程的能力
异步:在新的线程中执行任务,具备开启新线程的能力
2,并发和串行决定了任务的执行方式
并发:多个任务并发(同时)执行
串行:一个任务执行完毕后,再执行下一个任务
dispatch queues的使用:
分为:dispatch_async 和dispatch_sync
dispatch_sync(),同步添加操作。它是等待添加进队列里面的操作完成之后再继续执行下一个操作。
dispatch_async ,异步添加进任务队列,它不会做任何等待
1,Serial Queue 串行队列
又称为private dispatch queues,同时只执行一个任务。Serial queue通常用于同步访问特定的资源或数据。当你创建多个Serial queue时,同一个Serial queue(串行队列)内部各自是同步执行的,但Serial queue与Serial queue之间是可以并发执行的。
当想要任务按照某一个特定的顺序执行时,串行队列是很有用的。串行队列在同一个时间只执行一个任务。我们可以使用串行队列代替锁去保护共享的数据。和锁不同,一个串行队列可以保证任务在一个可预知的顺序下执行。
串行队列serial queues一般用于按顺序同步访问,可创建任意数量的串行队列,队列中的任务按照FIFO原理按顺序依次执行,各个串行队列之间是并发的。但是不能随意的大量生产Serial Dispatch Queue。每创建一个串行队列,系统就会对应创建一个线程,同时这些线程都是并行执行的,只是在串行队列中的任务是串行执行的。大量的创建串行队列会导致大量消耗内存,这是不可取的做法
创建一个串行队列
//第一个参数:queue的标识符,一般域名倒写+标识
//第二个参数:队列的类型,填NULL或是DISPATCH_QUEUE_SERIAL代表串行队列
dispatch_queue_t queue1 = dispatch_queue_create("com.zhiyou.queue1", DISPATCH_QUEUE_SERIAL);
2,Concurrent Queue 并行队列
并发队列创建多少都没有问题,因为Concurrent Dispatch Queue所使用的线程由系统的XNU内核高效管理,不会影响系统性能。
dispatch_queue_t queue2 = dispatch_queue_create("com.zhiyou.queue2", DISPATCH_QUEUE_CONCURRENT);
3,Main dispatch queue主队列和Global Dispatch Queue全局队列
系统为我们提供了两种调度队列 这两种队列不需要我们创建 只是在我们使用时获取一下
Main Dispatch Queue是在主线程中执行任务的Dispatch Queue。因为主线程只有一个,所以Main Dispatch Queue是Serial Dispatch Queue的一种。追加到Main Dispatch Queue中的任务将在主线程中执行。因为是在主线程中执行,所以应该只将用户界面更新等一些必须在主线程中执行的任务追加到Main Dispatch Queue中。
Global Dispatch Queue是全局都能使用的Concurrent Dispatch Queue(并行队列)。大多数情况下,可以不必通过dispatch_queue_create函数生成Concurrent Dispatch Queue,而是只需要获取Global Dispatch Queue使用即可。Global Dispatch Queue有四个优先级,分别是high、default、low、background。
通常,我们可以在global_queue中做一些long-running的任务,完成后在main_queue中更新UI,避免UI阻塞,无法响应用户操作:
可以同时运行多个任务,每个任务的启动时间是按照加入queue的顺序,结束的顺序依赖各自的任务.使用dispatch_get_global_queue获得.
//获取主队列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
//一般用此代码刷新UI
dispatch_async(mainQueue, ^{
NSLog(@"刷新UI");
});
//获取全局队列
//第一个参数:创建的队列类型
//第二个参数:优先级。默认优先级 为0
dispatch_queue_t gloableQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//想全局队列中添加任务
dispatch_async(gloableQueue, ^{
NSThread *currentThread = [NSThread currentThread];
NSLog(@">>>>>>当前线程是 %@",[currentThread isMainThread]?@"主线程啊":@"分线程了啦");
});
*/
/*
/*
注意:使用同步提交 调用此函数的队列和你同步提交任务的目标队列都是当前队列的话 会造成死锁
所谓死锁,通常指有两个线程A和B都卡住了,并等待对方完成某些操作。A不能完成是因为它在等待B完成。但B也不能完成,因为它在等待A完成。于是大家都完不成,就导致了死锁(DeadLock)
//例如:
//死锁1,同步死锁
dispatch_queue_t userQueue3 = dispatch_queue_create("com.zhiyou.userQueue1", DISPATCH_QUEUE_SERIAL);
dispatch_sync(userQueue3, ^{
NSLog(@">>>>>>>>>1111");
dispatch_sync(userQueue3, ^{
NSLog(@">>>>>>>>>2222");
});
NSLog(@">>>>>>>>>3333");
});
NSLog(@">>>>>>>>>4444");
死锁2:
//主队列 :串行队列;
//主线程执行dispatch_sync
//dispatch_sync让主线程执行task
//主线程执行task 发现dispatch_sync没有执行完 执行dispatch_sync发现task没有执行
dispatch_queue_t mainQueue = dispatch_get_main_queue() ;
dispatch_sync(mainQueue, ^{
NSLog(@"刷新 UI");
});
NSLog(@"我能不能执行");
创建和调用操作组
一个dispatch group可以用来将多个block组成一组以监测这些Block全部完成或者等待全部完成时发出的消息。使用函数dispatch_group_create来创建,然后使用函数dispatch_group_async来将block提交至一个dispatch queue,同时将它们添加至一个组
dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。这个方法很有用,比如你执行三个下载任务,当三个任务都下载完成后你才通知界面说完成的了
//创建一个组
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//向队列以及分组中添加任务
dispatch_group_async(group, globalQueue, ^{
NSLog(@"11111111.1....111");
NSThread *currentThread = [NSThread currentThread];
NSLog(@">>>111>>>当前线程是 %@",[currentThread isMainThread]?@"主线程啊":@"分线程了啦");
NSLog(@"11111111");
});
dispatch_group_async(group, globalQueue, ^{
NSLog(@"22222.222..222");
NSThread *currentThread = [NSThread currentThread];
NSLog(@">>>222>>>当前线程是 %@",[currentThread isMainThread]?@"主线程啊":@"分线程了啦");
NSLog(@"222222222");
});
dispatch_group_async(group, globalQueue, ^{
NSLog(@"3333.333..3333");
NSThread *currentThread = [NSThread currentThread];
NSLog(@">>>333>>>当前线程是 %@",[currentThread isMainThread]?@"主线程啊":@"分线程了啦");
NSLog(@"333333333");
});
//向分组中添加一个监听,用来监听添加到同一个分组中的队列的操作是否执行完毕,假如执行完毕,就可以执行其他操作
//第一个参数:监听的分组,
//第二个参数:监听的分组的队列名称
//第三个参数:执行的操作
dispatch_group_notify(group, globalQueue, ^{
//回到主线程刷新UI界面
dispatch_sync(dispatch_get_main_queue(), ^{
//刷新UI界面
NSLog(@"可以刷新UI界面啦");
});
});
*/
/*
dispatch_barrier_async的使用
经过上边的输出我们会发现,每一个任务的执行是并行的的,并且是没有先后顺序的。
dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行,也即为 dispatch_barrier_async一旦执行的时候,必须等到其执行完才能执行其他的操作
//创建自定义并行队列
dispatch_queue_t myQueue = dispatch_queue_create("com.zhiyou.myQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(myQueue, ^{
NSLog(@"111.11.11.11");
NSThread *currentThread = [NSThread currentThread];
NSLog(@">>>111>>>当前线程是 %@",[currentThread isMainThread]?@"主线程啊":@"分线程了啦");
NSLog(@"111111111");
});
dispatch_async(myQueue, ^{
NSLog(@"2222.222.222");
NSThread *currentThread = [NSThread currentThread];
NSLog(@">>>222>>>当前线程是 %@",[currentThread isMainThread]?@"主线程啊":@"分线程了啦");
NSLog(@"22222222");
});
dispatch_barrier_async(myQueue, ^{
NSLog(@"3333.333.333");
NSThread *currentThread = [NSThread currentThread];
NSLog(@">>>333>>>当前线程是 %@",[currentThread isMainThread]?@"主线程啊":@"分线程了啦");
NSLog(@"33333333");
});
dispatch_async(myQueue, ^{
NSLog(@"444.44..444");
NSThread *currentThread = [NSThread currentThread];
NSLog(@">>>4444>>>当前线程是 %@",[currentThread isMainThread]?@"主线程啊":@"分线程了啦");
NSLog(@"44444444");
});
dispatch_async(myQueue, ^{
NSLog(@"5555.5555.5..5");
NSThread *currentThread = [NSThread currentThread];
NSLog(@">>>555>>>当前线程是 %@",[currentThread isMainThread]?@"主线程啊":@"分线程了啦");
NSLog(@"555555");
});
*/
/*dispatch_apply
执行某个代码段N次
dispatch_queue_t globleQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//第一参数:执行次数
//第二个参数:执行的队列
//第三个参数:执行操作
dispatch_apply(5, globleQueue, ^(size_t index) {
NSLog(@"执行了啊啊啊啊");
});
//dispatch_release(globleQueue);
*/