ReentrantReadWriteLock 把锁拆成读锁(共享)和写锁(独占):多读并发、写独占、读写互斥,适合读远多于写的场景。支持可重入、公平性选择、锁降级(持有写锁时再获取读锁,随后释放写锁,保住读的一致性);不支持升级(读锁直接升写锁会死锁)。问题是写者可能饥饿——读者络绎不绝时写锁迟迟拿不到,JDK 对非公平模式的写者优先做了有限缓解。
StampedLock(Java 8)是改进版,提供三种模式:写锁、悲观读锁、乐观读。乐观读不拿锁:先 long stamp = tryOptimisticRead(),读完数据后 validate(stamp) 检查期间是否有写发生,有效则零锁开销,无效则降级为悲观读重读——在低写场景下读几乎无成本。但 StampedLock 不可重入、不支持 Condition,乐观读的使用模式容易写错(必须先读后验、失败重读),且返回的 stamp 语义与锁对象耦合。选型经验:读多写少且逻辑简单优先 StampedLock 乐观读;需要可重入、锁降级、Condition 时用 ReentrantReadWriteLock。追问方向:乐观读与 MVCC 的思想共性、LongAdder 这类无锁计数器为何常是更好的答案、AQS 如何用一个 state 同时表达读写两种锁(高低位切分)。
(约 450 字)