1️⃣ 核心结论
Barrier 是队列级别的调度控制,而锁是线程级别的互斥机制。它们的区别在于:控制粒度、性能优化方式,以及对并发资源的影响。
2️⃣ 控制粒度:队列 vs 线程
| 特性 | Barrier | NSLock / 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️⃣ 层级和语义
| 方面 | Barrier | Lock |
|---|---|---|
| 层级 | 队列级别调度 | 线程级别资源访问 |
| 顺序保证 | 队列内部任务顺序保证 | 不保证全局顺序,只保证互斥 |
| 作用域 | 自定义并发队列内部 | 任意共享资源 |
| 死锁风险 | 在队列内错误使用 sync + barrier 可能死锁 | 任意线程使用错误可能死锁 |
Barrier 本质上是 调度策略,锁本质上是 互斥机制
5️⃣ 使用场景对比
| 场景 | 推荐 |
|---|---|
| 共享资源读多写少,想最大化读性能 | Barrier + 自定义并发队列 |
| 临界区短且无法改成队列管理 | NSLock / os_unfair_lock |
| 跨多个队列或线程访问的共享资源 | 锁更可靠 |
| 仅在单队列内部管理并发 | Barrier 更高效 |
6️⃣ 总结一句话
Barrier 是队列级别的屏障,控制任务执行顺序以保证读写互斥;锁是线程级别的互斥机制,控制线程对共享资源的访问。Barrier 优化并发队列性能,锁是通用互斥工具。