很多人弄不懂这四个名词, 网上也有很多的误导. 对于线程死锁更是解释的五花八门, 煞有介事的样子.
一. 引出此文的元凶 --- 网上的曲解
这里讲解的煞有其事啊, 忽悠的我一愣一愣的, 任务 3 阻挡了任务 2 的执行, 那么我不写任务 3 的话是否就不死锁了呢?
经过我的代码验证, 事实是只写:
- // 当前队列为主队列
- dispatch_sync(dispatch_main_queue(),^ {
- NSLog(@"");
- });
复制代码
也会造成死锁, 说明什么任务 1,2,3 都是骗人的, 那到底是什么造成的思死锁呢??? 请认真看文章.
----- 装逼开始, 咳咳, 讲解开始 -----
二. 揭开背后的真相
####1. 先要知道概念 这里就真正的解释下他们的意思, 我们先抛出概念, 再列举例子, 再根据例子理解概念: 异步: sync 同步: async 队列: queue 串行: serial
并行 (并发):concurrent
queue: 队列分为串行和并行, 队列是任务的容器. 就像排队买东西, 串行是大家排成一队一个一个的买, 先来的先买, 后来的后买; 并行是大家并排排, 同时买, 谁先买完的看脸.
同步, 异步: 使用 dispatch_async: 调用一个 block, 这个 block 会被放到指定的 queue 队尾等待执行, 至于这个 block 是并行还是串行只和 dispatch_async 参数里面指定的 queue 是并行还是串行有关. 但是当前队列会直接跳过 block, 也就是不去管 block 的情况, dispatch_async 直接执行完毕
使用 dispatch_sync :dispatch_sync 方法会被加入当前队列, 而且 dispatch_sync 会等待 block 执行完毕才 return,block 被放到指定的 queue 上面执行, block 里的代码执行完 (即代码执行到 block 结束的}), 这时候整个 dispatch_sync 才算执行完.
说白了就是 dispatch_sync 正在出队列, 但是要等 block 执行完才能完全出队列.
下面看代码:
2. 死锁的犯人就是 --- 他自己
死锁发生在 当前队列为串行队列, 并通过 dispatch_sync 往当前队列添加了 task 的时候.
可以看出, 死锁的是队列, 而不是线程. 代码中, 第一个 dispatch_sync 并没有造成死锁, 就是因为 block 在另外的一个队列里, 而线程还是可以执行这个队列的任务的, 执行完之后, 队列就畅通了
2. 示例讲解各种组合情况
- - (void)test2 {
- NSLog(@"主线程");
- dispatch_queue_t concurrent = dispatch_queue_create("test.euque.concurrent", DISPATCH_QUEUE_CONCURRENT);
- dispatch_queue_t serial = dispatch_queue_create("test.queue.serial", DISPATCH_QUEUE_SERIAL);
- //async, 主线程不会等待 block 的完成, 会直接执行 gcd 之后的代码: NSLog(@"主线程任务结束")
- //task 进入 concurrent 并行队列, 由于是 async 所以允许 concurrent 开辟新线程
- dispatch_async(concurrent, ^{
- NSLog(@"concurrent_thread");
- //1. 再次开辟新线程运行: 1 秒后 NSLog(@"1");
- dispatch_async(concurrent, ^{
- [NSThread sleepForTimeInterval:1];
- NSLog(@"1");
- });
- //2. 由于是 sync,dispatch_sync 在 concurrent 队列中等待 block 执行结束
- //block 被加入 concurrent, 由于是并行, dispatch_sync 在队列里等待的时候并不耽误其他函数出队列, 所以 block 依旧可以出队列执行, 所以不会死锁.
- // sync 说明 block 在 concurrent_thread 线程中执行
- dispatch_sync(concurrent, ^{
- [NSThread sleepForTimeInterval:2];
- NSLog(@"2");
- });
- //3. NSLog(@"2") 运行结束后, async,concurrent_thread 不必等待 block 的执行, 直接前往 4
- //NSLog(@"3") 被加入 serial 队列, 出队列时 async 开辟新线程输出 3
- dispatch_async(serial, ^{
- NSLog(@"3");
- });
- //4. dispatch_sync 在 concurrent 中等待 block 的执行, block 添加到 serial 队列, sync 说明 block 交给 concurrent_thread 运行, 输出 4
- dispatch_sync(serial, ^{
- NSLog(@"4");
- });
- });
- NSLog(@"主线程任务结束");
- }
复制代码
3. 不同于自定义队列的主队列
- // 如果执行这个函数的队列就是 main_queue, 则会死锁
- dispatch_sync(dispatch_get_main_queue(), ^{
- });
- dispatch_async(dispatch_get_main_queue(), ^{
- });
复制代码
对于主队列来说, 无论是 sync 还是 async 都不会开辟新线程, 因为主队列的任务只在 main_thread 执行, 那么这两个函数的区别就是是否需要在当前队列中等待 block 执行完毕.
简书地址: https://www.jianshu.com/p/af68aab13c29
来源: https://juejin.im/post/5b4829a95188251b1c3ce66b