为什么aqs适用于写的场景?

1 个回答

  • 冰儿
    我疯狂地奔跑,只想为你承担一切的伤害,我竖起了山丘,不愿你看见我丑陋的脸庞。
    结论:**AQS 不是“只适用于写”,而是更适合“临界区较长或竞争激烈”的场景**——而**写操作**往往恰好具备这两个特征,所以常用 AQS(`ReentrantLock`、`ReentrantReadWriteLock.writeLock()`、`StampedLock.writeLock()` 等)。 为什么写场景更适合 AQS(而不是纯 CAS): 1. 竞争强 + 临界区不短 写操作常包含多步修改、校验、甚至 I/O。CAS 失败就自旋重试,竞争一大就白耗 CPU;AQS 直接**排队 + park/unpark**,把失败者挂起,**不空转**。 2. 需要一次锁住“多变量不变式” 写入常同时改多个字段/结构(维护一致性)。CAS 只能原子更新“一个内存位置”,实现复杂;锁能把临界区包起来,**一次性保护多个状态**。 3. 需要等待条件/顺序化 写入经常依赖条件(库存、缓冲区可写、批量窗口等)。AQS 自带 **Condition**,能 `await()/signal()`;CAS 没有条件队列,只能忙等或自造轮子。 4. 需要公平/可中断/可超时 写路径对**饥饿**更敏感(长期抢不到锁会卡业务)。AQS 支持**公平锁**、**中断获取**、**超时获取**;CAS 没有这些语义。 5. 更稳定的吞吐 高写入竞争下,CAS 的**重试风暴**(尤其多核)会拖垮吞吐;AQS 通过**串行化持有者**,让每次进入都能“把活干完”,整体更平滑。 什么时候仍优先 CAS * 写冲突少、临界区极短(比如单计数器)→ `AtomicLong` / `LongAdder`。 * 分片可消除热点(Striped/分段)→ CAS 也能跑得飞快。 简单选型口诀 * **短小 + 低竞争** → CAS。 * **长临界区 / 高竞争 / 需要条件或公平** → AQS(锁/信号量/闩)。 * **读多写少** → `ReentrantReadWriteLock` 或 `StampedLock`(乐观读),**写仍用 AQS 的独占模式**。 示意对比(高竞争写) ```java // CAS:可能大量自旋失败 while (true) { int v = counter.get(); if (counter.compareAndSet(v, v + 1)) break; // 高竞争下这里会频繁重试耗 CPU } // AQS:排队一次进入,做完再放 lock.lock(); try { // 多步修改,保障多变量不变式 } finally { lock.unlock(); } ``` 一句话:**写路径通常“长且挤”——用 AQS 更省心、更稳;写短且不挤,才用 CAS。**
    发布于 2025-08-18 03:53 •IP属地 上海
    举报
    评论
    收藏