并发与多线程:Java中实现可升级自定义ReadWriteLock并规避死锁
实现支持读锁升级的自定义ReadWriteLock(无死锁)
核心设计思路
普通java.util.concurrent.locks.ReadWriteLock不支持读锁升级为写锁,因为多个持有读锁的线程同时尝试升级会导致死锁。要实现安全的升级,必须保证:
- 升级操作是原子性的,不能在释放读锁和获取写锁之间让其他线程插入
- 只有当前线程是唯一的读锁持有者时,才能执行升级
- 设计写优先的锁策略,避免写锁饥饿,同时保证升级可靠性
具体实现代码
import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class UpgradeableReadWriteLock { private final ReentrantLock internalLock = new ReentrantLock(); private final Condition writersCondition = internalLock.newCondition(); private final Condition readersCondition = internalLock.newCondition(); private int readLockCount = 0; private Thread writeLockOwner = null; private int waitingWriters = 0; private final Map<Thread, Integer> readLockOwners = new HashMap<>(); // 获取读锁 public ReadLock readLock() { return new ReadLock(); } // 获取写锁 public WriteLock writeLock() { return new WriteLock(); } // 读锁升级为写锁的核心方法 public void upgrade() { internalLock.lock(); try { Thread currentThread = Thread.currentThread(); // 校验当前线程是唯一读锁持有者 Integer currentReadCount = readLockOwners.get(currentThread); if (currentReadCount == null || currentReadCount != readLockCount) { throw new IllegalMonitorStateException( "Only the sole read lock holder can upgrade to write lock" ); } // 原子性释放所有读锁 readLockCount -= currentReadCount; readLockOwners.remove(currentThread); // 持有写锁 writeLockOwner = currentThread; } finally { internalLock.unlock(); } } // 读锁内部实现 public class ReadLock implements java.util.concurrent.locks.Lock { @Override public void lock() { internalLock.lock(); try { Thread currentThread = Thread.currentThread(); // 有写锁持有者(非当前线程)或等待写线程时,阻塞读锁获取 while (writeLockOwner != null && writeLockOwner != currentThread || waitingWriters > 0) { readersCondition.await(); } // 更新当前线程的读锁持有计数 readLockOwners.put(currentThread, readLockOwners.getOrDefault(currentThread, 0) + 1); readLockCount++; } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { internalLock.unlock(); } } @Override public void unlock() { internalLock.lock(); try { Thread currentThread = Thread.currentThread(); Integer currentCount = readLockOwners.get(currentThread); if (currentCount == null || currentCount == 0) { throw new IllegalMonitorStateException("Thread does not hold read lock"); } // 递减读锁计数,清理无持有计数的线程 int newCount = currentCount - 1; if (newCount == 0) { readLockOwners.remove(currentThread); } else { readLockOwners.put(currentThread, newCount); } readLockCount--; // 读锁全部释放时,唤醒等待的写线程 if (readLockCount == 0) { writersCondition.signal(); } } finally { internalLock.unlock(); } } // Lock接口默认实现,可按需完善 @Override public void lockInterruptibly() throws InterruptedException { /* 实现略 */ } @Override public boolean tryLock() { /* 实现略 */ } @Override public boolean tryLock(long time, java.util.concurrent.TimeUnit unit) throws InterruptedException { /* 实现略 */ } @Override public Condition newCondition() { return internalLock.newCondition(); } } // 写锁内部实现 public class WriteLock implements java.util.concurrent.locks.Lock { @Override public void lock() { internalLock.lock(); try { waitingWriters++; // 有读锁持有者或写锁持有者非当前线程时,阻塞写锁获取 while (readLockCount > 0 || (writeLockOwner != null && writeLockOwner != Thread.currentThread())) { writersCondition.await(); } waitingWriters--; writeLockOwner = Thread.currentThread(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { internalLock.unlock(); } } @Override public void unlock() { internalLock.lock(); try { if (writeLockOwner != Thread.currentThread()) { throw new IllegalMonitorStateException("Thread does not hold write lock"); } writeLockOwner = null; // 先唤醒写线程(写优先),再唤醒读线程 writersCondition.signal(); readersCondition.signalAll(); } finally { internalLock.unlock(); } } // Lock接口默认实现,可按需完善 @Override public void lockInterruptibly() throws InterruptedException { /* 实现略 */ } @Override public boolean tryLock() { /* 实现略 */ } @Override public boolean tryLock(long time, java.util.concurrent.TimeUnit unit) throws InterruptedException { /* 实现略 */ } @Override public Condition newCondition() { return internalLock.newCondition(); } } }
无死锁的关键原因
- 原子升级操作:
upgrade()方法在内部锁internalLock的保护下,原子完成读锁释放和写锁获取,中间不会有其他线程插入修改锁状态 - 唯一读持有者校验:只有当前线程是唯一的读锁持有者时,才能执行升级,避免了多个读线程同时尝试升级导致的循环等待
- 写优先策略:等待写锁的线程会阻止新的读线程获取锁,既避免写锁饥饿,也防止在升级过程中出现新的读持有者
使用示例
public class UpgradeDemo { public static void main(String[] args) { UpgradeableReadWriteLock lock = new UpgradeableReadWriteLock(); UpgradeableReadWriteLock.ReadLock readLock = lock.readLock(); UpgradeableReadWriteLock.WriteLock writeLock = lock.writeLock(); // 先获取读锁 readLock.lock(); try { // 读取数据后判断需要修改 boolean needUpdate = true; if (needUpdate) { // 升级为写锁 lock.upgrade(); try { System.out.println("执行写操作(已完成读锁升级)"); } finally { // 释放写锁 writeLock.unlock(); } } } finally { // 注意:升级后读锁已被内部释放,此处不可再调用readLock.unlock() } } }
内容的提问来源于stack exchange,提问作者Ranushka Lakmal Sankalpa
相关产品推荐
相关产品推荐

