cas和aqs基于什么场景去使用?
1 个回答
我一路种下蘑菇,只为让你知道回家的路。龙傲天# 什么时候用 CAS(无锁/原子类/VarHandle) 适用条件(满足越多越合适): * **低\~中等竞争**:大多数时候一次 CAS 就成功;失败可少量自旋+退避。 * **临界区极短、纯 CPU 操作**:简单数值累加、标志位切换、轻量状态机。 * **不需要阻塞/条件队列**:失败就重试或返回即可。 * **可分片/分散写**:计数器、热点拆分(`LongAdder`/Striped64)。 * **需要无锁结构**:无锁队列/栈、环形缓冲(单/多生产者-消费者变体)。 典型用例: * 计数器/指标:`AtomicLong`(低竞争),`LongAdder`(高竞争分片)。 * 状态位/一次性动作:`compareAndSet(false,true)` 启停/去重。 * 乐观并发更新:基于版本号的 CAS(配 `AtomicStampedReference` 规避 ABA)。 * `ConcurrentHashMap` 内部桶级 CAS(插入/树化都靠它)。 不适用/要小心: * **高竞争**下自旋耗 CPU、可能活锁;需要退避或降级为锁。 * **需要条件等待**(例如“队列空了等待”)→ CAS 搞不定。 * **临界区较长/涉及 IO**:自旋期间浪费核。 # 什么时候用 AQS(可阻塞的队列化同步器) AQS = 队列 + CAS + park/unpark(如 `ReentrantLock`、`Semaphore`、`CountDownLatch`、`ReentrantReadWriteLock`、`StampedLock` 等) 适用条件: * **需要阻塞/唤醒**:等待资源、配额、阶段协作(闩、栅栏、信号量)。 * **竞争显著或临界区较长**:用**队列化**避免空转自旋。 * **需要公平/可重入/条件变量**:如 `Condition`、公平锁、读写分离。 * **需要组合语义**:共享/独占两种模式,多个等待集。 典型用例: * 互斥进入且临界区不短:`ReentrantLock`(默认非公平,高吞吐;需要先到先得就 `new ReentrantLock(true)`)。 * 多读少写:`ReentrantReadWriteLock` 或 `StampedLock`(乐观读)。 * 限流/并发窗口:`Semaphore`。 * 等待若干任务完成:`CountDownLatch`、`Phaser`。 * 需要条件等待/通知:`lock.newCondition().await()/signal()`。 不适用/要小心: * **极短临界区、低竞争**:AQS 的挂起/唤醒和排队开销相对更大。 * 过度追求公平会降吞吐(避免把所有锁都设公平)。 # 快速决策(口诀) * **短小、无阻塞、低竞争** → CAS/原子类(必要时 `LongAdder`)。 * **需要等待/唤醒、长临界区或竞争高** → AQS 同步器(锁/信号量/闩)。 * **既想无锁又要读多写少** → `StampedLock`(乐观读)或 RWLock。 * **CAS 失败频繁** → 加**指数退避**;仍不行就**降级为锁**。 * **有 ABA 风险** → 用 `AtomicStampedReference` / Markable 引用。 # 实战建议 * 计数/指标:优先 `LongAdder`(高并发写更稳),聚合时 `sum()`。 * 热点写 Map:先用 `compute`/`merge`(内部已做分段+CAS),别自己全局锁。 * 高并发队列:生产者/消费者短操作可 CAS,无界阻塞队列用 AQS(如 `LinkedBlockingQueue`)。 * 锁持有时间 > 几十微秒(做业务/IO)基本别自旋,直接 AQS 阻塞。 * 有**条件等待**需求(“等库存/等信号”)必须用 AQS 的 `Condition`/`Semaphore` 之类。 # 简短代码指路 * CAS 自旋(带退避): ```java for (int i = 0; i < 16; i++) { if (ref.compareAndSet(expect, update)) break; expect = ref.get(); Thread.onSpinWait(); if ((i & 3) == 3) Thread.yield(); // 退避 } ``` * AQS 锁 + 条件: ```java ReentrantLock lock = new ReentrantLock(); Condition notEmpty = lock.newCondition(); lock.lock(); try { while (q.isEmpty()) notEmpty.await(); // ... notEmpty.signal(); } finally { lock.unlock(); } ```发布于 2025-08-16 05:11 •IP属地 上海举报评论收藏
公众号进入网站体验更佳

