You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

并发与多线程:Java中实现可升级自定义ReadWriteLock并规避死锁

实现支持读锁升级的自定义ReadWriteLock(无死锁)

核心设计思路

普通java.util.concurrent.locks.ReadWriteLock不支持读锁升级为写锁,因为多个持有读锁的线程同时尝试升级会导致死锁。要实现安全的升级,必须保证:

  1. 升级操作是原子性的,不能在释放读锁和获取写锁之间让其他线程插入
  2. 只有当前线程是唯一的读锁持有者时,才能执行升级
  3. 设计写优先的锁策略,避免写锁饥饿,同时保证升级可靠性

具体实现代码

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(); }
    }
}

无死锁的关键原因

  1. 原子升级操作:upgrade()方法在内部锁internalLock的保护下,原子完成读锁释放和写锁获取,中间不会有其他线程插入修改锁状态
  2. 唯一读持有者校验:只有当前线程是唯一的读锁持有者时,才能执行升级,避免了多个读线程同时尝试升级导致的循环等待
  3. 写优先策略:等待写锁的线程会阻止新的读线程获取锁,既避免写锁饥饿,也防止在升级过程中出现新的读持有者

使用示例

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 03:52:38