通过 GCD,开发者不用再直接跟线程打交道了,只需要向队列中添加代码块即可,GCD 在后端管理着一个线程池。GCD 不仅决定着你的代码块将在哪个线程被执行,它还根据可用的系统资源对这些线程进行管理。这样可以将开发者从线程管理的工作中解放出来,通过集中的管理线程,来缓解大量线程被创建的问题
先弄清几个概念
同步:在当前线程中执行,没有开线程的能力(dispatch_sync)
异步:在新的线程中执行,有开线程的能力(dispatch_async)
串行队列:任务一个接一个的执行
并发队列:让多个任务并发(同时)执行,只有在开启线程即异步函数(dispatch_async)下有效(例如下面全局队列同步执行无效)
队列:有三种队列
主队列:是一种串行队列,能够保证任务一个接一个的执行,比较特殊的是它是唯一一个可以刷新UI的队列,所有刷新UI的操作都必须在主队列中执行,实际应用中是在子线程中执行接收数据的耗时操作,接收完成后再在主线程中刷新UI界面 用 dispatch_get_main_quene() 得到
全局队列:是一种并发队列,有四种优先级background default ,low high 用 dispatch_get_global_quene() 得到
自定义队列:可以是串行队列也可以是并发队列(取决于参数) 用disaptch_quene_create()得到
使用:
1、主线程
1️⃣主队列中使用异步执行
dispatch_queue_t mainQuene = dispatch_get_main_queue();
NSLog(@"开始执行");
dispatch_async(mainQuene, ^{
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"在主队列中使用异步执行");
});
NSLog(@"结束执行");
执行结果
2016-12-27 10:55:21.482 GCD[932:79002] 开始执行
2016-12-27 10:55:21.483 GCD[932:79002] 结束执行
2016-12-27 10:55:21.491 GCD[932:79002] <NSThread: 0x6000000771c0>{number = 1, name = main}
2016-12-27 10:55:21.491 GCD[932:79002] 在主队列中使用异步执行
2️⃣主队列中使用同步执行
dispatch_queue_t mainQuene = dispatch_get_main_queue();
NSLog(@"开始执行");
dispatch_sync(mainQuene, ^{
NSLog(@"在主队列中使用同步执行");
});
NSLog(@"结束执行");
这里会报错:原因是产生了死锁 。 这些代码是在viewDidload中执行中,主队列是串行队列,只能一个接一个任务的执行,本身就在执行,这里添加了一个任务到主队列,并且是同步执行,造成了互相等待的死锁
2、全局队列
1️⃣全局队列中同步执行
//同步执行不开启新线程,队列中的所有任务都是在本身所在队列中(现在是主队列)执行,并且是顺序执行
dispatch_queue_t globalQuene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_sync(globalQuene, ^{
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"1===");
});
dispatch_sync(globalQuene, ^{
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"2===");
});
dispatch_sync(globalQuene, ^{
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"3===");
});
dispatch_sync(globalQuene, ^{
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"4===");
});
执行结果
2016-12-27 11:17:10.733 GCD[995:90895] <NSThread: 0x60800007c600>{number = 1, name = main}
2016-12-27 11:17:10.733 GCD[995:90895] 1===
2016-12-27 11:17:10.734 GCD[995:90895] <NSThread: 0x60800007c600>{number = 1, name = main}
2016-12-27 11:17:10.734 GCD[995:90895] 2===
2016-12-27 11:17:10.734 GCD[995:90895] <NSThread: 0x60800007c600>{number = 1, name = main}
2016-12-27 11:17:10.734 GCD[995:90895] 3===
2016-12-27 11:17:10.734 GCD[995:90895] <NSThread: 0x60800007c600>{number = 1, name = main}
2016-12-27 11:17:10.734 GCD[995:90895] 4===
2️⃣全局队列异步执行
//异步执行不开启新线程,队列中的任务在开启的新线程中执行,开启的线程的数量不定,并且执行的顺序也不定
dispatch_queue_t globalQuene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(globalQuene, ^{
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"1===");
});
dispatch_async(globalQuene, ^{
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"2===");
});
dispatch_async(globalQuene, ^{
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"3===");
});
dispatch_async(globalQuene, ^{
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"4===");
});
执行结果
2016-12-27 11:18:55.217 GCD[1012:93021] <NSThread: 0x608000267280>{number = 5, name = (null)}
2016-12-27 11:18:55.217 GCD[1012:93007] <NSThread: 0x608000267340>{number = 3, name = (null)}
2016-12-27 11:18:55.217 GCD[1012:93005] <NSThread: 0x6080002674c0>{number = 6, name = (null)}
2016-12-27 11:18:55.217 GCD[1012:93004] <NSThread: 0x6000002621c0>{number = 4, name = (null)}
2016-12-27 11:18:55.217 GCD[1012:93021] 3===
2016-12-27 11:18:55.217 GCD[1012:93007] 1===
2016-12-27 11:18:55.217 GCD[1012:93005] 4===
2016-12-27 11:18:55.217 GCD[1012:93004] 2===
//参数1 队列的名称,命名规则为应用名称id的倒序 参数2 如果是null 则创建的队列为串行队列 如果是DISPATCH_QUEUE_CONCURRENT 则创建的队列是并发队列
dispatch_queue_t currentQuene = dispatch_queue_create("current", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"开始");
dispatch_async(currentQuene, ^{
NSLog(@"当前线程1:%@",[NSThread currentThread]);
});
dispatch_async(currentQuene, ^{
NSLog(@"当前线程2:%@",[NSThread currentThread]);
});
dispatch_async(currentQuene, ^{
NSLog(@"当前线程3:%@",[NSThread currentThread]);
});
NSLog(@"结束");
执行结果
2016-12-27 11:37:41.282 GCD[1109:108111] 开始
2016-12-27 11:37:41.282 GCD[1109:108111] 结束
2016-12-27 11:37:41.282 GCD[1109:108148] 当前线程2:<NSThread: 0x600000076900>{number = 4, name = (null)}
2016-12-27 11:37:41.282 GCD[1109:108145] 当前线程1:<NSThread: 0x608000070cc0>{number = 3, name = (null)}
2016-12-27 11:37:41.282 GCD[1109:108162] 当前线程3:<NSThread: 0x608000071840>{number = 5, name = (null)}
总结:
主队列 | 全局队列 | 自定义队列(串行) | 自定义队列(并发) | |
async(异步) |
未开新线程
顺序执行
|
开新线程
异步执行
|
开新线程
同步执行
|
开新线程
异步执行
|
sync(同步) |
死锁
|
未开新线程
顺序执行
|
未开新线程
顺序执行
|
未开新线程
顺序执行
|
注:
1、在主队列中不能使用同步执行函数(会产生死锁)
2、只有异步执行函数才具有开新线程的能力
3、并发队列只在异步函数中有效(如果想要一个任务异步执行,必须在并发队列中使用异步函数执行)