当前线程为主线程时如何跳过DispatchQueue调度避免挂起?
解决DispatchQueue主线程方法并发挂起问题的正确实现
这其实是个很常见的GCD优化场景,核心思路就是先判断当前是否已经处于主线程,再决定是直接执行闭包还是调度到主线程队列,既能避免不必要的队列调度开销,也能解决并发调用时任务堆积导致的挂起问题。
直接上可复用的代码实现:
class DispatchQueueHandler { static func runOnMain(completion: @escaping () -> Void) { // 先检查当前线程是否为主线程 if Thread.isMainThread { // 已经在主线程,直接执行completion闭包 completion() } else { // 不在主线程,调度到主线程异步执行 DispatchQueue.main.async(execute: completion) } } }
为什么这样能解决挂起问题?
- 当你的方法被并发调用且其中一部分调用已经在主线程执行时,旧实现会把所有任务都塞进主线程的串行队列,导致队列堆积大量待执行任务,进而引发线程挂起。现在主线程内的调用会直接执行,不会进入队列排队,大大减轻了主线程队列的压力。
- 避免了不必要的异步调度延迟:主线程队列是串行队列,每一个异步任务都要等待前面的任务完成,直接执行能让任务立刻得到处理,提升响应速度。
关键注意事项
- 绝对不要用
DispatchQueue.main.sync处理非主线程的情况!如果不小心在主线程调用sync,会直接触发死锁——主线程会等待自己的队列执行任务,而队列又被主线程阻塞,形成循环等待。 - 如果你的
completion闭包存在重入风险(比如闭包内部又调用了这个方法),需要确保业务逻辑是线程安全的,但这种直接执行的方式本身是完全符合GCD设计规范的。
内容的提问来源于stack exchange,提问作者Syed Qamar Abbas
相关产品推荐
相关产品推荐

