DispatchQueue.main线程安全:主队列任务是否可无中断执行完成?
结论
你给出的这段代码不存在线程安全隐患,点击按钮时永远不会读到count的异常中间状态。
核心原因说明
1. 主队列与主线程的执行特性
主队列是GCD提供的全局唯一绑定主线程的串行队列,二者的执行逻辑可以明确为:
- 所有提交到主队列的任务,只会在主线程执行,不存在被调度到其他线程运行的可能
- 主线程由RunLoop驱动,无论是主队列派发的任务,还是系统投递的UI点击、界面刷新等事件,都会被串行调度:单次取出的任务/事件会完整执行到结束,才会开始处理下一个排队的逻辑,不会出现任务执行到一半被同属主线程的其他逻辑插队打断的情况。
2. 对应到你的代码场景
你代码里所有涉及count读写的逻辑,全部运行在主线程主队列上:
modifyCount()是通过DispatchQueue.main.asyncAfter提交到主队列的任务,每次执行时对count的读取、自增、取模、赋值整套操作会完整跑完,才会让出执行权给主队列后续排队的任务- 按钮点击触发的闭包属于系统UI事件,会被封装成任务投递到主队列排队,它和
modifyCount()的任务永远不会并行执行,只会按入队顺序先后完整运行。
3. 关于“非原子操作风险”的澄清
你担心的非原子赋值导致的中间状态问题,触发前提是多线程并发读写同一块内存:比如一个线程正在对变量进行写入操作还没完成,另一个线程同时发起读取,才会拿到脏数据。
你的代码里完全不存在多线程并发访问count的场景,所有读写都被串行调度在主线程执行,自然不会触发非原子操作的线程安全问题。
4. 关于主线程与主队列的概念差异
你提到的二者概念区分确实存在:主线程是操作系统层面的执行线程,主队列是GCD层面的任务调度队列,主线程除了处理主队列任务,还会处理RunLoop的其他事件源(触摸事件、界面刷新、端口消息等)。但这种概念差异不会带来你担心的执行打断问题:RunLoop在单轮循环中处理某一类事件时,不会跳转到其他事件源执行逻辑,只要你不主动写阻塞主线程的同步等待代码(比如在主线程调用DispatchQueue.main.sync触发死锁,或是跨队列同步等待其他线程返回结果),所有主线程上的逻辑都会按调度顺序无中断执行完成。
内容的提问来源于stack exchange,提问作者Torrontés
相关产品推荐
相关产品推荐

