【作者前言】:13年入圈,分享些本人工作中遇到的点点滴滴那些事儿,17年刚开始写博客,高手勿喷!以分享交流为主,欢迎各路豪杰点评改进!
1.应用场景:
多线程神器---GCD,很多开发的场景中,我们都会使用到。
2.实现目标:
针对面试中可能遇到的问题,进行反向的剖析知识点。
3.代码说明:【比喻~队列与函数存在一种关系:C4-2的组合关系】
1) 知识点预热:首先需要了解同步&异步、串行&并行的关系
-
同步执行:
dispatch_sync(),这个函数会把一个block加入到指定的队列中,而且会一直等到执行完blcok,这个函数才返回。因此在block执行完之前,调用dispatch_sync方法的线程是阻塞的。 !>!>!即需要等待执行结果后再执行其他任务
-
异步执行
dispatch_async(),这个函数也会把一个block加入到指定的队列中,但是和同步执行不同的是,这个函数把block加入队列后不等block的执行就立刻返回了。 !>!>!即 无需等待执行结果,继续执行其他任务
小结:
dispatch_async() 和 dispatch_sync() 他们的作用是将 任务(block)添加进指定的队列中。并根据是否为sync决定调用该函数的线程是否需要阻塞。
!!!:这里调用该函数的线程并不执行 参数中指定的任务(block块),任务的执行者是GCD分配给任务所在队列的线程。
即 ---> 调用dispatch_sync() 和 dispatch_async() 的线程,并不一定是任务(block块)的真正执行者
-
串行队列
如dispatch_get_main_queue() 该队列中所有任务都是串行依次执行,可以保证在执行某个任务时,在它前面进入队列的所有任务肯定执行完了。对于每一个不同的串行队列,系统会为这个队列建立唯一的线程来执行代码
-
并行队列
如dispatch_get_global_queue() 该队列中的任务它们的执行结束时间是不确定的,取决于每个任务的耗时。并发队列中的任务:GCD会动态分配多条线程来执行。具体几条线程取决于当前内存使用状况,线程池中线程数等因素
2) 代码实操+详细解读分析
- 【主队列---串行同步】
/** 主队列---串行同步 --测试
不会开启线程 等待执行
*/
- (void)mainSyncTest {
NSLog(@"0");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"1");
});
NSLog(@"2");
}
/****************控制台输出结果*******************/
0 --- >崩溃Thread 1: EXC_BAD_INSTRUCTION 造成死锁
/****************结果分析******************/
打印 0 ---> 正常输出后,
当前执行这个dispatch_get_main_queue()队列的是主线程。
执行了dispatch_sync()函数后,将block(打印1) 添加到了main_queue中,
同时调用dispatch_syn这个函数的线程(也就是主线程)会被阻塞,需要等待
block(打印1)执行完成,而此时执行主线程队列任务的线程正是主线程,
此时他处于阻塞状态,所以block(打印1)永远不会被执行,因此主线程一直处于阻塞状态。
因此这段代码运行后,并非卡在block(打印1)中无法返回,而是根本无法执行到这个block(打印1)!
导致你等我我等你,形成死锁。无法打印 1 和 2
- 【主队列---串行异步】
/** 主队列---串行异步 --测试
不会开启线程, 顺序执行
*/
- (void)mainAysncTest {
NSLog(@"0");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"1");
});
NSLog(@"2");
}
/****************控制台输出结果******************/
0 2 1
/****************结果分析******************/
dispatch_get_main_queue()属于串行队列,顺序执行
dispatch_async()异步调用,不需要等待直接输出执行结果,
即 0 ---> 2 ---> 1
- 【全局队列---并行同步】
/** 全局队列---并行同步 --测试
不会开辟线程!
*/
- (void)globalSyncTest {
for (int i = 0; i < 5; i ++) {
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
NSLog(@"%d -- %@",i,[NSThread currentThread]);
});
}
for (long i = 0; i < 100000; i ++) {
//相当于做个一定的延时处理...方便查看效果
}
NSLog(@"hello sync Global_Queue");
}
/****************控制台输出结果******************/
0 -- <NSThread: 0x6000003faa40>{number = 1, name = main}
1 -- <NSThread: 0x6000003faa40>{number = 1, name = main}
2 -- <NSThread: 0x6000003faa40>{number = 1, name = main}
3 -- <NSThread: 0x6000003faa40>{number = 1, name = main}
4 -- <NSThread: 0x6000003faa40>{number = 1, name = main}
hello sync Global_Queue
/****************结果分析******************/
dispatch_get_global_queue() 属于并行队列,结果无序
dispatch_sync() 同步调用,需要等待执行结束后在执行其他任务,
即 阻塞当前线程,顺序执行,故并行也无法发挥作用,需要一个等一个依次执行,
所以这里并没有开辟新的线程!
- 【全局队列---并行异步】
/** 全局队列---并行异步 --测试
*/
- (void)globalAsyncTest {
for (int i = 0; i < 5; i ++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"%d -- %@",i,[NSThread currentThread]);
});
}
for (long i = 0; i < 100000; i ++) {
//相当于做个一定的延时处理...方便查看效果
}
NSLog(@"hello async Global_Queue");
}
/****************控制台输出结果******************/
0 -- <NSThread: 0x6000032ae000>{number = 3, name = (null)}
2 -- <NSThread: 0x6000032ae0c0>{number = 6, name = (null)}
1 -- <NSThread: 0x6000032adfc0>{number = 4, name = (null)}
3 -- <NSThread: 0x600003292940>{number = 5, name = (null)}
4 -- <NSThread: 0x6000032ae000>{number = 3, name = (null)}
hello async Global_Queue
/****************结果分析******************/
dispatch_get_global_queue() 属于并行队列,执行结果时序不一定
dispatch_async()异步调用,不需要等待直接顺序执行,
所以,线程并非只有一个,开辟了多个线程并行处理任务,输出的结果的顺序也不确定
- 【通用的串行同步】
/** 串行同步队列 --测试
不开辟线程 顺序执行
*/
- (void)serialSyncTest {
dispatch_queue_t serialQueue = dispatch_queue_create("ypSerialQueue", DISPATCH_QUEUE_SERIAL);
for (int i = 0; i < 5; i ++) {
dispatch_sync(serialQueue, ^{
NSLog(@"%d -- %@",i, [NSThread currentThread]);
});
}
NSLog(@"hello sync serialQueue");
}
/****************控制台输出结果******************
0 -- <NSThread: 0x600000365200>{number = 1, name = main}
1 -- <NSThread: 0x600000365200>{number = 1, name = main}
2 -- <NSThread: 0x600000365200>{number = 1, name = main}
3 -- <NSThread: 0x600000365200>{number = 1, name = main}
4 -- <NSThread: 0x600000365200>{number = 1, name = main}
hello sync serialQueue
*/
/****************结果分析******************
serialQueue 属于串行队列 不会开辟线程 顺序执行
dispatch_sync()同步调用,需要等待 顺序执行,
串行队列情况下,只能依次执行,同步调用 等待出结果,故输出如上
*/
- 【通用的串行异步】
/** 串行异步队列 --测试
不开辟线程 顺序执行
*/
- (void)serialAsyncTest {
dispatch_queue_t serialQueue = dispatch_queue_create("ypSerialQueue", DISPATCH_QUEUE_SERIAL);
for (int i = 0; i < 5; i ++) {
dispatch_async(serialQueue, ^{
NSLog(@"%d -- %@",i, [NSThread currentThread]);
});
}
NSLog(@"hello serial Queue");
}
/****************控制台输出结果******************
hello serial Queue
0 -- <NSThread: 0x600003904d40>{number = 3, name = (null)}
1 -- <NSThread: 0x600003904d40>{number = 3, name = (null)}
2 -- <NSThread: 0x600003904d40>{number = 3, name = (null)}
3 -- <NSThread: 0x600003904d40>{number = 3, name = (null)}
4 -- <NSThread: 0x600003904d40>{number = 3, name = (null)}
*/
/****************结果分析******************
serialQueue 属于串行队列 不会开辟线程 顺序执行
dispatch_async()异步调用,不需要等待直接顺序执行,
串行队列情况下,只能依次执行,异步调用直接出结果,故输出如上
*/
- 【通用的并行同步】
/** 并行同步 ---测试
不会创建线程 顺序执行
*/
- (void)concurrentSyncTest {
//创建并发队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("ypConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 5; i ++) {
dispatch_sync(concurrentQueue, ^{
NSLog(@"%d -- %@",i, [NSThread currentThread]);
});
}
NSLog(@"hello sync concurrent Queue");
}
/****************控制台输出结果******************
0 -- <NSThread: 0x6000020ee940>{number = 1, name = main}
1 -- <NSThread: 0x6000020ee940>{number = 1, name = main}
2 -- <NSThread: 0x6000020ee940>{number = 1, name = main}
3 -- <NSThread: 0x6000020ee940>{number = 1, name = main}
4 -- <NSThread: 0x6000020ee940>{number = 1, name = main}
hello sync concurrent Queue
*/
/****************结果分析******************
concurrentQueue 属于并行队列,执行结果时序不一定
dispatch_sync()同步调用,需要等待 顺序执行,
只要同步 就等待执行, 所以没有开辟线程 结果如上
*/
- 【通用的并行异步】
/** 并行异步:*/
- (void)concurrentAsyncTest {
//创建并发队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("ypconcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 5; i ++) {
dispatch_async(concurrentQueue, ^{
NSLog(@"%d -- %@",i, [NSThread currentThread]);
});
}
for (long i = 0; i < 100000; i ++) {
//相当于做个一定的延时处理...方便查看效果
}
NSLog(@"hello concurrent Queue");
}
/****************控制台输出结果******************/
0 -- <NSThread: 0x600001633600>{number = 3, name = (null)}
3 -- <NSThread: 0x600001633580>{number = 5, name = (null)}
2 -- <NSThread: 0x60000160d380>{number = 4, name = (null)}
1 -- <NSThread: 0x600001633500>{number = 6, name = (null)}
4 -- <NSThread: 0x600001633580>{number = 5, name = (null)}
hello concurrent Queue
/****************结果分析******************/
concurrentQueue 属于并行队列,执行结果时序不一定
dispatch_async() 异步调用,不需要等待直接顺序执行,
所以,线程并非只有一个,开辟了多个线程并行处理任务,输出的结果的顺序也不确定
网友评论