一、什么是GCD
GCD:grand central dispatch 牛逼的中枢调度器
特点:
1.纯C语言API
2.apple官方出品
3.自动管理生命周期(ARC中)
4.只需要告诉GCD需要执行的任务,操作简单
二、GCD的使用
1、队列的使用和创建
队列:存放需要执行的任务的容器。而执行这些任务的是线程。队列不一定创建线程,如果不创建线程,则当前线程来执行这些队列中的任务。
创建串行队列
/**
创建队列
@param "concurrentQueue" 队列名称
@param DISPATCH_QUEUE_CONCURRENT 队列类型,CONCURRENT为并发队列,NULL为串行队列
@return 队列
*/
dispatch_queue_t t3 = dispatch_queue_create("serialQueue", NULL);
获取全局并发队列
/**
直接获取全局并发队列
@param QOS_CLASS_DEFAULT 优先级别,有两种方式表示,详见API官方注释
@param 0 预留参数,传0
@return 全局并发队列
*/
dispatch_queue_t t1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
创建并发队列
/**
创建队列
@param "concurrentQueue" 队列名称
@param DISPATCH_QUEUE_CONCURRENT 队列类型,CONCURRENT为并发队列,NULL为串行队列
@return 队列
*/
dispatch_queue_t t2 = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
2、执行任务
任务的执行步骤:创建任务和队列后,将任务添加到队列中,最后根据asyn和syn来判断是否需要创建线程以及在哪个线程执行
异步执行队列中的任务
dispatch_async(queue, ^{
NSLog(@"1---%@",[NSThread currentThread]);
});
同步执行队列中的任务
dispatch_sync(queue, ^{
NSLog(@"1---%@",[NSThread currentThread]);
});
三、四种情况
1、串行队列同步执行
- (void)syncTaskWithSerialQueue {
NSLog(@"syncTaskWithSerialQueue---start");
dispatch_queue_t queue = dispatch_queue_create("serialQueue", NULL);
dispatch_sync(queue, ^{
sleep(1);
NSLog(@"1---%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
sleep(1);
NSLog(@"2---%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
sleep(1);
NSLog(@"3---%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
sleep(1);
NSLog(@"4---%@",[NSThread currentThread]);
});
NSLog(@"syncTaskWithSerialQueue---end");
}
结果:
2018-11-21 15:25:03.037 XKQuote[51245:4129046] syncTaskWithSerialQueue---start
2018-11-21 15:25:04.037 XKQuote[51245:4129046] 1---{number = 1, name = main}
2018-11-21 15:25:05.038 XKQuote[51245:4129046] 2---{number = 1, name = main}
2018-11-21 15:25:06.040 XKQuote[51245:4129046] 3---{number = 1, name = main}
2018-11-21 15:25:07.040 XKQuote[51245:4129046] 4---{number = 1, name = main}
2018-11-21 15:25:07.041 XKQuote[51245:4129046] syncTaskWithSerialQueue---end
总结:
1.串行队列中同步执行任务不会创建线程,在当前线程中执行
2.顺序执行
3.阻塞当前线程
4.同步执行会等待当前队列中的任务执行完毕,才会接着执行
2、串行队列异步执行
- (void)asyncTaskWithSerialQueue {
NSLog(@"asyncTaskWithSerialQueue---start");
dispatch_queue_t queue = dispatch_queue_create("serial2", NULL);
dispatch_async(queue, ^{
sleep(1);
NSLog(@"asyncTaskWithSerialQueue:1---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
sleep(1);
NSLog(@"asyncTaskWithSerialQueue:2---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
sleep(1);
NSLog(@"asyncTaskWithSerialQueue:3---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
sleep(1);
NSLog(@"asyncTaskWithSerialQueue:4---%@",[NSThread currentThread]);
});
NSLog(@"asyncTaskWithSerialQueue---end");
}
结果
2018-11-22 15:01:42.505 XKQuote[14265:4858578] asyncTaskWithSerialQueue---start
2018-11-22 15:01:42.506 XKQuote[14265:4858578] asyncTaskWithSerialQueue---end
2018-11-22 15:01:43.510 XKQuote[14265:4858727] asyncTaskWithSerialQueue:1---{number = 2, name = (null)}
2018-11-22 15:01:44.514 XKQuote[14265:4858727] asyncTaskWithSerialQueue:2---{number = 2, name = (null)}
2018-11-22 15:01:45.518 XKQuote[14265:4858727] asyncTaskWithSerialQueue:3---{number = 2, name = (null)}
2018-11-22 15:01:46.523 XKQuote[14265:4858727] asyncTaskWithSerialQueue:4---{number = 2, name = (null)}
总结
1.开启了线程,但是只开启了一个;
2.所有任务都在开启的那个线程中按顺序执行
3、并行队列同步执行
- (void)syncTaskWithConcurrentQueue {
NSLog(@"syncTaskWithConcurrentQueue---begin");
dispatch_queue_t queue = dispatch_queue_create("concurrent1", DISPATCH_QUEUE_CONCURRENT);
// dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_sync(queue, ^{
NSLog(@"syncTaskWithConcurrentQueue:1---%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"syncTaskWithConcurrentQueue:2---%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"syncTaskWithConcurrentQueue:3---%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"syncTaskWithConcurrentQueue:4---%@",[NSThread currentThread]);
});
NSLog(@"syncTaskWithConcurrentQueue---end");
}
结果
2018-11-22 15:05:25.698 XKQuote[14338:4863404] syncTaskWithConcurrentQueue---begin
2018-11-22 15:05:26.700 XKQuote[14338:4863404] syncTaskWithConcurrentQueue:1---{number = 1, name = main}
2018-11-22 15:05:27.701 XKQuote[14338:4863404] syncTaskWithConcurrentQueue:2---{number = 1, name = main}
2018-11-22 15:05:28.702 XKQuote[14338:4863404] syncTaskWithConcurrentQueue:3---{number = 1, name = main}
2018-11-22 15:05:29.703 XKQuote[14338:4863404] syncTaskWithConcurrentQueue:4---{number = 1, name = main}
2018-11-22 15:05:29.704 XKQuote[14338:4863404] syncTaskWithConcurrentQueue---end
总结
1.并行队列中同步执行不会创建新的线程;
2.在当前线程中顺序执行,会阻塞线程;
3.并发的前提是多线程
4.同步执行会等待当前队列中的任务执行完毕,才会接着执行
4、并行队列异步执行
- (void)asyncTaskWithConcurrentQueue {
NSLog(@"asyncTaskWithSerialQueue---start");
dispatch_queue_t queue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
sleep(1);
NSLog(@"1---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
sleep(1);
NSLog(@"2---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
sleep(1);
NSLog(@"3---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
sleep(1);
NSLog(@"4---%@",[NSThread currentThread]);
});
NSLog(@"syncTaskWithSerialQueue---end");
}
2018-11-21 16:11:31.372 XKQuote[51304:4131596] asyncTaskWithSerialQueue---start
2018-11-21 16:11:31.372 XKQuote[51304:4131596] syncTaskWithSerialQueue---end
2018-11-21 16:11:32.372 XKQuote[51304:4183129] 1---{number = 6, name = (null)}
2018-11-21 16:11:32.372 XKQuote[51304:4187339] 2---{number = 7, name = (null)}
2018-11-21 16:11:32.373 XKQuote[51304:4187341] 4---{number = 8, name = (null)}
2018-11-21 16:11:32.373 XKQuote[51304:4187340] 3---{number = 9, name = (null)}
总结
1.并行队列异步执行创建了新的队列(具体创建几个队列由GCD自己控住)
2.不阻塞当前线程;
3.不是顺序执行(对比:gropu,优先级)
大总结
sync+serial = sync + concurrent
async+serial:新开一个线程顺序执行
async+concurrent:新开多个线程异步执行
并发的前提是多线程
并发和串行是相对于队列来说的,指的是队列中任务的执行顺序,同步和异步针对的是任务执行是否需要立即返回返回值
同步执行会等待当前队列中的任务执行完毕,才会接着执行后面的代码
四、两种特殊情况
主线程中同步执行
- (void)mainQueueSyncTask {
NSLog(@"mainQueueSyncTask---start");
dispatch_queue_t t = dispatch_get_main_queue();
dispatch_sync(t, ^{
NSLog(@"1---%@",[NSThread currentThread]);
});
dispatch_sync(t, ^{
NSLog(@"2---%@",[NSThread currentThread]);
});
dispatch_sync(t, ^{
NSLog(@"3---%@",[NSThread currentThread]);
});
dispatch_sync(t, ^{
NSLog(@"4---%@",[NSThread currentThread]);
});
NSLog(@"mainQueueSyncTask---end");
}
结果:
2018-11-22 15:54:56.523 XKQuote[14542:4908219] mainQueueSyncTask---start
原因:
线程是执行任务的,队列是存放任务的。当主线程执行完主队列中的ABCD...等,走到mainQueueSyncTask方法时,mainQueueSyncTask就相当于主线程正在处理的一个任务,而此时执行到dispatch_sync,此时会在主队列中添加一个任务,暂成为newTask,也就是排在mainQueueSyncTask后面的任务,而同步执行需要马上执行任务,而主线程现在正在执行mainQueueSyncTask这个方法,所以dispatch_sync在等待主线程。而主线程在执行mainQueueSyncTask方法中的dispatch_sync这一步,只有这一步返回了结果,mainThread才会继续往下执行到NSLog(@"end")结束,再去执行newTask,所以形成了相互的等待;
步骤简析:
1.mainQueueSyncTask执行NSLog完毕
2.执行dispatch_sync(),未返回,等待主线程执行后返回结果
3.主队列等待dispatch_sync()返回后执行mainQueueSyncTask方法中的下一步
4.循环等待
换各种方法:
dispatch_queue_t t = dispatch_queue_create("serialQueue", 0);
// dispatch_queue_t t = dispatch_get_main_queue();
NSLog(@"%@",[NSThread currentThread]);
dispatch_sync(t, ^{
NSLog(@"%@",[NSThread currentThread]);
});
NSLog(@"xxx");
结果:
2019-06-15 07:04:51.450024+0800 XKSqlite3[64298:2020687] {number = 1, name = main}
2019-06-15 07:04:51.450251+0800 XKSqlite3[64298:2020687] {number = 1, name = main}
2019-06-15 07:04:55.336086+0800 XKSqlite3[64298:2020687] xxx
注意:
1、注意输出,执行的线程都在主线程;
2、成功执行完成,没有发生堵塞;
原因:
1、队列只是存放任务,dispatch_get_main_queue()也只是获取主队列,而不是主线程。
2、在哪个线程执行,是否新开线程执行这些都是GCD自己控制,队列永远是存放任务的,而线程是执行任务的。
3、任务没有存放在朱队列,就不存在排队等待的情况,所以并不会发生堵塞。
非主线程中在主队列中同步执行任务
- (void)mainQueueSyncTaskInSubThread {
// initWithBlock方法在10.0以后再能使用
NSThread *thread = [[NSThread alloc] initWithBlock:^{
NSLog(@"mainQueueSyncTask---start");
NSLog(@"%@",[NSThread currentThread]);
dispatch_queue_t t = dispatch_get_main_queue();
dispatch_sync(t, ^{
NSLog(@"1---%@",[NSThread currentThread]);
});
dispatch_sync(t, ^{
NSLog(@"2---%@",[NSThread currentThread]);
});
dispatch_sync(t, ^{
NSLog(@"3---%@",[NSThread currentThread]);
});
dispatch_sync(t, ^{
NSLog(@"4---%@",[NSThread currentThread]);
});
NSLog(@"mainQueueSyncTask---end");
}];
[thread start];
}
结果
2018-11-22 16:05:43.285 XKQuote[14826:4922979] mainQueueSyncTask---start
2018-11-22 16:05:43.286 XKQuote[14826:4922979] {number = 4, name = (null)}
2018-11-22 16:05:43.298 XKQuote[14826:4922657] 1---{number = 1, name = main}
2018-11-22 16:05:43.299 XKQuote[14826:4922657] 2---{number = 1, name = main}
2018-11-22 16:05:43.300 XKQuote[14826:4922657] 3---{number = 1, name = main}
2018-11-22 16:05:43.301 XKQuote[14826:4922657] 4---{number = 1, name = main}
2018-11-22 16:05:43.302 XKQuote[14826:4922979] mainQueueSyncTask---end
原因:
之所以不循环等待,是执行dispatch_sync时,去到了mainThread执行,而当前thread执行的是mainQueueSyncTaskInSubThread方法,当然不会循环等待。特别注意执行dispatch_sync之前的NSLog,表明当前线程不是主线程
主队列异步执行
- (void)AsyncTaskWithMainQueue {
NSLog(@"AsyncTaskWithMainQueue---start");
NSLog(@"%@",[NSThread currentThread]);
dispatch_queue_t t = dispatch_get_main_queue();
dispatch_async(t, ^{
NSLog(@"1---%@",[NSThread currentThread]);
});
dispatch_async(t, ^{
NSLog(@"2---%@",[NSThread currentThread]);
});
dispatch_async(t, ^{
NSLog(@"3---%@",[NSThread currentThread]);
});
dispatch_async(t, ^{
NSLog(@"4---%@",[NSThread currentThread]);
});
NSLog(@"AsyncTaskWithMainQueue---end");
}
结果
2018-11-22 16:20:54.298 XKQuote[17987:4947380] AsyncTaskWithMainQueue---start
2018-11-22 16:20:54.299 XKQuote[17987:4947380] {number = 1, name = main}
2018-11-22 16:20:54.299 XKQuote[17987:4947380] AsyncTaskWithMainQueue---end
2018-11-22 16:20:54.307 XKQuote[17987:4947380] 1---{number = 1, name = main}
2018-11-22 16:20:54.307 XKQuote[17987:4947380] 2---{number = 1, name = main}
2018-11-22 16:20:54.308 XKQuote[17987:4947380] 3---{number = 1, name = main}
2018-11-22 16:20:54.308 XKQuote[17987:4947380] 4---{number = 1, name = main}
原因
主队列异步执行的区别就是异步会直接返回结果,所以执行完方法之后才会去执行dispatch_async