面试问题:仅用volatile能否实现ReadWriteLock?原子类+volatile方案?
仅用volatile能实现ReadWriteLock吗?
先给明确结论:仅靠volatile变量,不可能实现一个能在多线程并发场景下正确工作的ReadWriteLock。
volatile的作用只是保证变量的可见性和禁止指令重排序,但它不提供原子性——而读写锁的核心逻辑,比如统计活跃读线程的数量、切换读写状态这些操作,都需要原子性来避免竞态条件。
不过你面试时面试官提到的“仅用volatile实现”,大概率是指一种简化到有明显缺陷的“玩具版”读写锁,只能在极低并发(比如最多一个写线程、读线程不会同时抢锁)的场景下勉强跑起来,比如下面这个例子:
class VolatileBasedRWLock { // 0=无锁,1=写锁持有,>1=读锁数量 private volatile int state = 0; public void lockRead() { // 自旋等写锁释放 while (state == 1) { // 空循环忙等 } // 这里的state++不是原子操作!多线程同时调用会计数错乱 state++; } public void unlockRead() { state--; } public void lockWrite() { // 自旋等所有读/写锁释放 while (state != 0) { // 空循环忙等 } state = 1; } public void unlockWrite() { state = 0; } }
这个实现的致命问题是state++和state--是拆分的读-改-写操作,完全不原子。当多个读线程同时调用lockRead()时,会出现多个线程同时读到同一个state值,然后各自加1,最终导致读计数被覆盖,写线程可能永远无法获取锁——这显然不是一个可用的读写锁,只是利用volatile的可见性做了状态同步,但核心的原子操作缺失。
结合原子类与volatile实现正确的无锁ReadWriteLock
要做一个能正确工作的无锁读写锁,必须用原子类(比如AtomicInteger)来处理状态的原子更新——其实原子类内部已经用了volatile变量(比如AtomicInteger的value字段就是volatile的),所以本质是用原子类的CAS操作来弥补volatile缺少的原子性。
下面是一个典型的无锁读写锁实现思路:
class AtomicRWLock { // 用AtomicInteger的高16位存写锁状态,低16位存读锁计数 private final AtomicInteger state = new AtomicInteger(0); private static final int WRITE_LOCK_FLAG = 0xFFFF0000; private static final int READ_LOCK_COUNT_MASK = 0x0000FFFF; private static final int READ_LOCK_INCREMENT = 1; private static final int WRITE_LOCK_SET = 0x00010000; public void lockRead() { int currentState; do { currentState = state.get(); // 写锁被持有,自旋等待 if ((currentState & WRITE_LOCK_FLAG) != 0) { continue; } // CAS原子增加读计数,失败就重试 } while (!state.compareAndSet(currentState, currentState + READ_LOCK_INCREMENT)); } public void unlockRead() { // 原子减少读计数 state.getAndAdd(-READ_LOCK_INCREMENT); } public void lockWrite() { int currentState; do { currentState = state.get(); // 有读锁或写锁被持有,自旋等待 if (currentState != 0) { continue; } // CAS原子设置写锁位,失败就重试 } while (!state.compareAndSet(currentState, currentState | WRITE_LOCK_SET)); } public void unlockWrite() { // 重置状态为无锁 state.getAndSet(0); } }
这个实现的核心逻辑:
- 用一个
AtomicInteger的高低位分离写锁状态和读锁计数,通过位运算快速判断当前锁状态 - 读锁获取:先检查写锁是否被占用,再用CAS原子增加读计数,确保多线程下计数正确
- 写锁获取:检查是否有任何读/写锁在使用,再用CAS原子抢占写锁位
- 所有状态更新都是原子操作,配合自旋实现无锁等待,同时原子类内部的volatile字段保证了状态的可见性
最后总结
- 仅用volatile做不出可用的ReadWriteLock,因为没有原子操作支持,必然出现竞态条件
- 面试官说的“仅用volatile实现”应该是指那种有缺陷的简化版本,只能在极端低并发场景下用,完全不具备生产价值
- 正确的无锁读写锁必须结合原子类的CAS操作,用原子性更新来避免竞态,同时利用原子类内置的volatile保证状态可见
内容的提问来源于stack exchange,提问作者Dmytro
相关产品推荐
相关产品推荐

