1-17.【GCD】barrier 和锁(NSLock / os_unfair_lock)的本质区别?

6 阅读2分钟

1️⃣ 核心结论

Barrier 是队列级别的调度控制,而锁是线程级别的互斥机制。它们的区别在于:控制粒度、性能优化方式,以及对并发资源的影响。


2️⃣ 控制粒度:队列 vs 线程

特性BarrierNSLock / os_unfair_lock
控制对象队列内部任务执行顺序临界区或资源访问线程
互斥范围队列内的任务任意线程对同一资源的访问
保证屏障任务独占队列(前后任务按序)同一时间只有一个线程持有锁
队列类型依赖只对自定义并发队列有效对任何线程都有效

✅ 核心:Barrier 保证队列内部的执行顺序,锁保证线程之间的互斥访问


3️⃣ 并发性能优化

Barrier 的优势

  • 并发队列的读任务可以同时执行
  • 写任务(Barrier)独占执行
  • 不阻塞系统线程池,只阻止队列内部任务派发
  • 适合 读多写少 的场景
let queue = DispatchQueue(label: "concurrentQueue", attributes: .concurrent)
queue.async { read() }
queue.async(flags: .barrier) { write() } // 写独占队列
queue.async { read() }

读任务仍然并发执行,不像锁会阻塞线程


锁的特性

  • 任意线程访问临界区时必须先获取锁
  • 同一时间只能有一个线程进入
  • 如果锁被占用,线程会阻塞(或自旋)
  • 不区分“队列前后”,只保证互斥
let lock = NSLock()
lock.lock()
sharedArray.append(1)
lock.unlock()
  • 如果多个线程同时想访问 sharedArray,都会排队等待锁
  • 阻塞线程 → 性能可能下降

4️⃣ 层级和语义

方面BarrierLock
层级队列级别调度线程级别资源访问
顺序保证队列内部任务顺序保证不保证全局顺序,只保证互斥
作用域自定义并发队列内部任意共享资源
死锁风险在队列内错误使用 sync + barrier 可能死锁任意线程使用错误可能死锁

Barrier 本质上是 调度策略,锁本质上是 互斥机制


5️⃣ 使用场景对比

场景推荐
共享资源读多写少,想最大化读性能Barrier + 自定义并发队列
临界区短且无法改成队列管理NSLock / os_unfair_lock
跨多个队列或线程访问的共享资源锁更可靠
仅在单队列内部管理并发Barrier 更高效

6️⃣ 总结一句话

Barrier 是队列级别的屏障,控制任务执行顺序以保证读写互斥;锁是线程级别的互斥机制,控制线程对共享资源的访问。Barrier 优化并发队列性能,锁是通用互斥工具。