首先来回忆几个概念:
- 任务:需要执行的操作;
- 队列:储存任务的数据结构;
- 同步:只能开启一个子线程执行队列;
- 异步:可开启多个子线程执行队列;
- 串行:同一时间只能执行一个任务;
- 并行:同一时间可执行多个任务;
假设你已经了解上面几个概念,那么我们开始通过几个案例来了解一下死锁:
案例一
|
|
打印结果:
|
|
分析:
dispatch_get_main_queue表示运行在主线程的主队列;dispatch_sync表示是一个同步线程;2是同步线程的主队列的任务;
首先执行1 ,是没有问题的,只是接下来,程序遇到了同步线程 dispatch_sync ,那么它会进入队列,等待2 执行完,然后执行3。但这是队列,有任务来,当然会将任务加到队尾部,然后遵循先入先出的原则执行任务,那么,2 就会被加到最后,3 排在 2 的前面。
使用 dispatch_sync 执行 mainQueue 时, mainQueue 存放着两个任务 1、3 ,使用 block 加入了 2 以后,mainQueue 变成 1、3、2 ,但在执行上,是 1、2、3 ,所以执行队列到 2 时,2 需要等 3 先执行完,但是因为 dispatch_sync 是同步函数,不执行完 2 ,是不会执行 3 的,所以 2 和 3 就进入了互相等的状态,死锁发生。
图解:

案例二
|
|
打印结果:
|
|
分析:
dispatch_get_global_queue表示是一个全局并行队列;dispatch_sync表示是一个同步线程;2是同步线程的全局并行队列的任务;
首先执行 1 ,接下来遇到一个同步线程,程序会进入等待,等待任务 2 完成以后,才会继续执行任务 3 ,从 dispatch_get_global_queue 可以看出,2 被加入一个全局并行队列中,当 2 执行以后,不等待结果,返回到主队列,继续执行 3。
图解:

案例三
|
|
打印结果:
|
|
分析:
这个案例没有使用系统提供的串行或并行队列,而是自己通过 dispatch_queue_creat 创建了DISPATCH_QUEUE_SERIAL 的串行队列。
- 执行
1; - 遇到异步线程,将
2、同步线程、4加入串行队列,因为是异步线程,所以主线程中的5不必等待异步线程内的任务执行完毕; - 因为
5不需要等待,所以异步线程里的2,和主线程中的5,执行顺序不能确定; 2执行完以后,遇到同步线程,这时将3加入串行队列;- 又因为
4比3先加入串行队列,所以4执行完以后3才会执行,但是同步线程要执行完3才能返回,所以造成死锁。
图解:

案例四
|
|
打印结果:
|
|
分析:
首先,主线程的队列是 mainQueue ,任务是:1、异步线程、5 ;
异步线程的队列是 globalQueue ,任务是:2、同步线程、4
- 主线程中执行
1,然后遇到异步函数 ,将2、同步线程、4加入并行队列; - 开线程,因为
2在异步线程,所以2和5的执行顺序随机,但在同一级运行; - 异步线程中遇到同步线程,执行主队列,将
3加入到主队列,这时3 在 5的后面; - 这时
5,已经执行完,所以3可以执行,然后执行4。
从以上分析看,2 和 5 的输出顺序不确定,但是 5 一定在 3 前面,3 一定在 4 前面;
图解:

案例五
|
|
打印结果:
|
|
分析:
首先来看下,加进了哪些任务:
mainQueue 里面有 异步线程、4、死循环、5 ,globalQueue 里面有 1、同步线程、3 。
- 异步线程,所以
4不用等,1和4的顺序随机; - 主线程遇到死循环,所以
5不会执行,异步线程中遇到同步线程执行主队列,2在5的后面,因为5不会执行,所以2是死锁,所以3也不会执行。
最终结果是 1 和 4,执行顺序随机。
图解:
