DispatchQueue是否锁内部资源?跨线程访问共享资源需加锁吗?
DispatchQueue 对闭包内共享资源的防护逻辑说明
核心结论
DispatchQueue 不会自动锁定、防护闭包内部引用的任何共享资源。它的核心能力是按照队列预设的调度规则(串行/并行、QoS等级、线程绑定关系)执行提交的闭包任务,完全没有内置的资源访问识别、并发冲突检测逻辑。
结合示例代码的拆解
你给出的实现代码如下:
class Factory { var localSharedResource var localQueue = DispatchQueue(label: "localQueue") let threadLock = NSLock() func modify(){ localQueue.async { self.threadLock.lock() localSharedResource = "a change is made here" self.threadLock.unlock() } } }
针对你提出的“如果localSharedResource同时会被其他线程访问,是否还需要锁防护”的问题,可以分场景明确判断标准:
- 如果项目中所有对
localSharedResource的读、写操作,全部统一提交到这个默认创建的串行localQueue上执行,那你连threadLock都不需要加。因为无特殊配置的DispatchQueue默认是串行队列,天然保证队列内的任务不会并发执行,对资源的所有访问都是顺序完成的,不存在数据竞争风险。 - 只要存在任意一处对
localSharedResource的访问,没有被收口到这个localQueue上(比如直接在主线程读取该属性、提交到其他队列修改该值),就必须做并发防护。这种情况下你在队列闭包内部加NSLock的写法是起不到防护作用的:因为锁的生效前提是所有访问共享资源的代码路径,都先获取同一个锁实例,绕过队列的外部访问路径根本没有获取这把锁的逻辑,和队列内的写操作会形成跨线程并发,触发不可预期的数据错乱。 - 如果你给
localQueue配置了.concurrent属性,那就算所有访问都在这个队列上,也需要额外做防护,因为并行队列的任务是并发执行的,本身就不保证资源访问的顺序安全。
常见认知误区
很多开发者会误以为“把任务丢到队列里就自动线程安全了”,本质上是混淆了队列的调度能力和资源防护能力——队列只管自己队列内的任务执行规则,管不到队列外的代码对共享资源的操作,更不会自动帮你给资源加锁。
内容的提问来源于stack exchange,提问作者George Termentzoglou
相关产品推荐
相关产品推荐

