1️⃣ 场景示例
DispatchQueue.main.sync {
print("在主线程同步调度自己")
}
- 当前线程:主线程
- 目标队列:主队列(串行队列)
我们分析它的调度过程。
2️⃣ 主队列的调度模型
-
主队列 = 串行队列
- 队列内部只有一个线程执行 block → FIFO 顺序
- 队列上的任务必须按顺序执行
-
主线程就是执行主队列任务的线程
- 所有主队列 block 都在主线程上执行
-
串行 + 单线程 = 任务执行互斥
3️⃣ sync 调度机制
-
sync的行为:- 将 block 添加到目标队列末尾
- 阻塞调用线程,直到 block 执行完成
-
注意:sync 会等待 block 执行完成再返回
4️⃣ 死锁发生的原理
逐步分析:
-
当前在 主线程上执行任务 A(或者直接在主线程执行)
-
调用
DispatchQueue.main.sync { 任务 B }- 任务 B 被 加入主队列尾部
-
sync阻塞当前线程(主线程)等待任务 B 完成 -
但 主线程正被阻塞,无法执行队列上的任务 B
-
队列中的任务 B 永远无法开始 → 任务 A 永远等待
✅ 双方互相等待 → 死锁
4.1 用调度模型图理解
主线程 (执行主队列)
└─ sync {任务B} --> 阻塞主线程等待任务B执行
主队列 FIFO:
[任务B] <-- 等待主线程空闲
- 主线程被 sync 阻塞
- 队列的 FIFO block(任务 B)无法执行
- 永远无法完成 → 死锁
5️⃣ 异步和并发的对比
| 调度方式 | 线程是否阻塞 | 会死锁吗? |
|---|---|---|
| sync 到同串行队列 | 阻塞调用线程 | ✅ 死锁 |
| async 到同串行队列 | 不阻塞 | ❌ 安全 |
| sync 到并发队列 | 阻塞当前线程 | ⚠️ 可能阻塞,但不一定死锁(取决于线程池) |
| async 到并发队列 | 不阻塞 | ✅ 安全 |
核心区别:阻塞 + 串行队列 + 同线程执行 = 死锁
6️⃣ 结论
为什么主线程 sync 到主队列一定死锁:
- 主队列是 串行队列
- 所有任务在 主线程执行
sync阻塞调用线程(主线程)等待队列任务完成- 队列任务需要 主线程执行
- 主线程被阻塞,队列任务无法执行 → 死锁
💡 一句话总结:
主线程 sync 到主队列一定死锁,因为 主队列的唯一线程(主线程)被阻塞等待自己队列里的任务完成,而这个任务又必须在主线程上执行,形成互相等待的死锁循环。