一、在GCD中常见的名次解释:
名词解释
GCD:全称是Grand Central Dispatch,中文名字大脑中枢派发,基于C语言的是苹果公司为解决多核并行问题研发,线程及生命周期都有系统自动管理。
任务:执行什么操作
队列:用来存放任务,将需要执行的任务添加到队列中,队列会遵循FIFO原则(先进先出、后进后出),将队列中的任务取出,放到对应的线程中执行
同步:不创建新的线程,只在当前线程中执行任务
异步:创建多条线程执行任务
串行:同一时间每次只能执行一个任务,当前任务未完成下一个任务只能在队列中等候
并发:同一时间可以执行多个任务
死锁:两个或多个任务互相等待形成死循环阻塞了线程,甚至导致应用无响应
二、关系表

三、示例代码
//串行队列
dispatch_queue_t serial_queue = dispatch_queue_create("custom.serial.queue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(serial_queue, ^{
NSLog(@"------这是串行队列同步任务----%@-------%@",[NSThread currentThread],[NSThread mainThread]);
});
dispatch_async(serial_queue, ^{
NSLog(@"------这是串行队列异步任务----%@-------%@",[NSThread currentThread],[NSThread mainThread]);
});
//并行队列
dispatch_queue_t concurrent_queue = dispatch_queue_create("custom.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(concurrent_queue, ^{
NSLog(@"------这是并行队列同步任务----%@-------%@",[NSThread currentThread],[NSThread mainThread]);
});
dispatch_async(concurrent_queue, ^{
NSLog(@"------这是并行队列异步任务----%@-------%@",[NSThread currentThread],[NSThread mainThread]);
});
//主队列
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"------这是主队列同步任务----%@-------%@",[NSThread currentThread],[NSThread mainThread]);
});
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"------这是主队列异步任务----%@-------%@",[NSThread currentThread],[NSThread mainThread]);
});
1、以上代码运行到主队列同步任务时就会因为线程阻塞导致程序奔溃。当我们暂时注释主队列同步任务,然后运行示例代码,控制台输出如下结果:
------这是串行队列同步任务----<NSThread: 0x600000840f00>{number = 1, name = main}-------<NSThread: 0x600000840f00>{number = 1, name = main}
------这是并行队列同步任务----<NSThread: 0x600000840f00>{number = 1, name = main}-------<NSThread: 0x600000840f00>{number = 1, name = main}
------这是串行队列异步任务----<NSThread: 0x600000805280>{number = 7, name = (null)}-------<NSThread: 0x600000840f00>{number = 1, name = (null)}
------这是并行队列异步任务----<NSThread: 0x60000084ff40>{number = 4, name = (null)}-------<NSThread: 0x600000840f00>{number = 1, name = (null)}
------这是主队列异步任务----<NSThread: 0x600000840f00>{number = 1, name = main}-------<NSThread: 0x600000840f00>{number = 1, name = main}
2、回到刚才的问题,为什么在主队列执行同步任务会出现线程阻塞呢?
因为主线程的任务时按顺序执行,开启同步任务后,主队列在执行到同步任务的时候,开始执行同步任务,但是同步任务又处于等待上一个任务执行完成,线程就会出现阻塞,这就是导致死锁的原因,所以在只用GCD的同步任务需要注意当前队列处于主队列还是其他队列。
四、并发队列
1、名词语解释
并发队列:指在同一时间间隔内执行多个任务,同一时间内只有一个任务在执行
并行队列:指在同一时刻执行多个任务,同一时间内可能有多个任务在执行
2、线程优先级
DISPATCH_QUEUE_PRIORITY_HIGH: QOS_CLASS_USER_INITIATED //高优先级
DISPATCH_QUEUE_PRIORITY_DEFAULT: QOS_CLASS_DEFAULT //默认优先级
DISPATCH_QUEUE_PRIORITY_LOW: QOS_CLASS_UTILITY //最低优先级
DISPATCH_QUEUE_PRIORITY_BACKGROUND: QOS_CLASS_BACKGROUND //程序后台执行
3、示例代码
//并发队列
dispatch_group_t global = dispatch_group_create();
//低优先任务
dispatch_queue_global_t low_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
//高优先任务
dispatch_queue_global_t high_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
//默认
dispatch_queue_global_t default_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_global_t back_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_group_async(global, low_queue, ^{
for (int i = 0; i < 10; i++) {
NSLog(@"---%@",[NSThread currentThread]);
}
});
dispatch_group_async(global, high_queue, ^{
for (int i = 0; i < 10; i++) {
NSLog(@"===%@",[NSThread currentThread]);
}
});
dispatch_group_async(global, default_queue, ^{
for (int i = 0; i < 10; i++) {
NSLog(@"+++%@",[NSThread currentThread]);
}
});
dispatch_group_async(global, back_queue, ^{
for (int i = 0; i < 10; i++) {
NSLog(@"^^^%@",[NSThread currentThread]);
}
});
输出结果:
+++<NSThread: 0x600003752a80>{number = 4, name = (null)}
===<NSThread: 0x600003732a80>{number = 5, name = (null)}
===<NSThread: 0x600003732a80>{number = 5, name = (null)}
+++<NSThread: 0x600003752a80>{number = 4, name = (null)}
+++<NSThread: 0x600003752a80>{number = 4, name = (null)}
===<NSThread: 0x600003732a80>{number = 5, name = (null)}
===<NSThread: 0x600003732a80>{number = 5, name = (null)}
+++<NSThread: 0x600003752a80>{number = 4, name = (null)}
===<NSThread: 0x600003732a80>{number = 5, name = (null)}
+++<NSThread: 0x600003752a80>{number = 4, name = (null)}
===<NSThread: 0x600003732a80>{number = 5, name = (null)}
+++<NSThread: 0x600003752a80>{number = 4, name = (null)}
===<NSThread: 0x600003732a80>{number = 5, name = (null)}
+++<NSThread: 0x600003752a80>{number = 4, name = (null)}
===<NSThread: 0x600003732a80>{number = 5, name = (null)}
+++<NSThread: 0x600003752a80>{number = 4, name = (null)}
===<NSThread: 0x600003732a80>{number = 5, name = (null)}
+++<NSThread: 0x600003752a80>{number = 4, name = (null)}
===<NSThread: 0x600003732a80>{number = 5, name = (null)}
---<NSThread: 0x600003752b00>{number = 3, name = (null)}
^^^<NSThread: 0x600003745740>{number = 6, name = (null)}
+++<NSThread: 0x600003752a80>{number = 4, name = (null)}
---<NSThread: 0x600003752b00>{number = 3, name = (null)}
---<NSThread: 0x600003752b00>{number = 3, name = (null)}
^^^<NSThread: 0x600003745740>{number = 6, name = (null)}
---<NSThread: 0x600003752b00>{number = 3, name = (null)}
---<NSThread: 0x600003752b00>{number = 3, name = (null)}
---<NSThread: 0x600003752b00>{number = 3, name = (null)}
^^^<NSThread: 0x600003745740>{number = 6, name = (null)}
---<NSThread: 0x600003752b00>{number = 3, name = (null)}
---<NSThread: 0x600003752b00>{number = 3, name = (null)}
---<NSThread: 0x600003752b00>{number = 3, name = (null)}
^^^<NSThread: 0x600003745740>{number = 6, name = (null)}
---<NSThread: 0x600003752b00>{number = 3, name = (null)}
^^^<NSThread: 0x600003745740>{number = 6, name = (null)}
^^^<NSThread: 0x600003745740>{number = 6, name = (null)}
^^^<NSThread: 0x600003745740>{number = 6, name = (null)}
^^^<NSThread: 0x600003745740>{number = 6, name = (null)}
^^^<NSThread: 0x600003745740>{number = 6, name = (null)}
^^^<NSThread: 0x600003745740>{number = 6, name = (null)}
从上面输出结果就可以看出并发队列的执行优先级,但是很多时候,我们需要做的任务不是这种,而是并发执行多个任务,等待所有任务完成后,再去执行某个操作,例如:
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("com.uploadfile", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"000000");
//子任务一
dispatch_group_async(group, queue, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"111111");
}
});
NSLog(@"222222");
//子任务二
dispatch_group_async(group, queue, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"333333");
}
});
NSLog(@"444444");
//所有任务完成后
dispatch_group_notify(group, queue, ^{
NSLog(@"555555");
});
控制台输出结果:
2020-04-30 15:44:34.419697+0800 11111111[48973:413079] 000000
2020-04-30 15:44:34.419773+0800 11111111[48973:413079] 222222
2020-04-30 15:44:34.419783+0800 11111111[48973:413241] 111111
2020-04-30 15:44:34.419839+0800 11111111[48973:413079] 444444
2020-04-30 15:44:34.419845+0800 11111111[48973:413241] 111111
2020-04-30 15:44:34.419853+0800 11111111[48973:413240] 333333
2020-04-30 15:44:34.419905+0800 11111111[48973:413241] 111111
2020-04-30 15:44:34.419913+0800 11111111[48973:413240] 333333
2020-04-30 15:44:34.419968+0800 11111111[48973:413241] 111111
2020-04-30 15:44:34.420209+0800 11111111[48973:413240] 333333
2020-04-30 15:44:34.420366+0800 11111111[48973:413241] 111111
2020-04-30 15:44:34.420390+0800 11111111[48973:413240] 333333
2020-04-30 15:44:34.420683+0800 11111111[48973:413240] 333333
2020-04-30 15:44:34.420846+0800 11111111[48973:413240] 555555
分析:其中for循环是为了模拟耗时操作,执行一些耗时任务,可以从打印结果中看出,dispatch_group_notify是等待所有子任务完成后再去执行,比如我们批量上传图片或者文件,然后最后通知用户上传完成,UI更新等操作。
五、面试题
1、GCD是否可以取消某个任务?
答案:是可以的,GCD为我们提供了取消任务的api,接下来继续看下示例
dispatch_queue_t queue = dispatch_queue_create("com.uploadImage", DISPATCH_QUEUE_CONCURRENT);
dispatch_block_t block1 = dispatch_block_create(0, ^{
NSLog(@"1");
});
dispatch_block_t block2 = dispatch_block_create(0, ^{
NSLog(@"2");
});
dispatch_block_t block3 = dispatch_block_create(0, ^{
NSLog(@"3");
});
dispatch_async(queue, block1);
dispatch_async(queue, block2);
dispatch_async(queue, block3);
dispatch_block_cancel(block1);
以下是输出结果:
2020-04-30 16:14:03.941828+0800 11111111[57038:453729] 2
2020-04-30 16:14:03.941828+0800 11111111[57038:453731] 3
2、如何利用GCD实现想要执行的所有任务执行完成后,再去执行其他任务?
这个知识点就是考虑栅栏函数了,GCD的功能很强大,虽然有一些瑕疵,但是基本能够满足日常需求。
void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block);
这个就是栅栏函数,这个函数会阻塞线程,直到在Block块内的代码执行完成后,才能执行后面的代码。
到此基本上常用的GCD相关的面试内容基本完成了,有问题欢迎@我,qq群:960744862
网友评论