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

Java实现兼顾读写公平的读写者问题程序运行卡死问题排查

读写者公平实现代码问题排查与修复

核心问题根源

  • 计数器逻辑错误(最核心卡死原因):Reader线程中,读申请阶段仅对readWait执行了1次自增,但是读结束阶段连续执行了2次readWait.getAndDecrement(),直接导致readWait计数变为负数,后续条件判断完全失效,无法正确唤醒写者线程。
  • 等待条件逻辑错误:混淆了「等待线程计数」和「活跃线程计数」的职责:预先定义的readActive/writeActive两个活跃计数变量完全没有使用,反而在判断阻塞条件时错误使用等待计数作为判断依据,导致线程阻塞逻辑不符合读写者规则。
  • 队列锁未正确释放导致死锁:线程获取queue锁后,如果触发await逻辑会自动释放lock锁,但不会释放已经持有的queue锁,其余所有线程都会卡在queue.lock()步骤无法进入,直接导致全局死锁。
  • 通知逻辑错误:当前仅使用signal()唤醒单个等待线程,存在多个等待线程时无法全部唤醒,比如有多个读者等待时,单次唤醒只能启动一个读者,剩余读者会永久阻塞。

修复方案

  1. 明确变量职责:
    • readWait:等待读的线程数
    • readActive:正在读的线程数
    • writeWait:等待写的线程数
    • writeActive:正在写的线程数
  2. 调整加锁逻辑:queue锁仅用于控制线程进入等待队列的顺序,拿到进入权限后立即释放,不要持有queue锁进入await逻辑
  3. 修正计数器操作:读申请时readWait自增,拿到读权限后readWait自减、readActive自增;读结束时readActive自减
  4. 修正阻塞条件:
    • 读者阻塞条件:存在活跃写者writeActive.get()>0 或者 存在等待写者writeWait.get()>0(保证公平,不让写者饥饿)
    • 写者阻塞条件:存在活跃读者readActive.get()>0 或者 存在活跃写者writeActive.get()>0
  5. 替换signal()为signalAll(),确保所有符合条件的等待线程都能被唤醒

修复后核心代码示例

public class ReaderWriter {
    static Lock lock = new ReentrantLock();
    static Lock queue = new ReentrantLock();
    static Condition read  = lock.newCondition(); 
    static Condition write = lock.newCondition(); 
    static AtomicInteger readWait = new AtomicInteger(0);
    static AtomicInteger readActive = new AtomicInteger(0);
    static AtomicInteger writeWait= new AtomicInteger(0);
    static AtomicInteger writeActive = new AtomicInteger(0);
    static StringBuilder str = new StringBuilder();
    static int val = 0;
    static class ReaderThread extends Thread {
        @Override
        public void run() {
            try {
                // queue锁仅控制排队顺序,不持有进入后续逻辑
                queue.lock();
                lock.lock();
                readWait.getAndIncrement();
                queue.unlock();
                
                // 有写者活跃或等待时阻塞,保证公平
                while (writeActive.get() > 0 || writeWait.get() > 0 ) 
                    read.await();
                readWait.getAndDecrement();
                readActive.getAndIncrement();
                lock.unlock();
                
                // 模拟读操作
                System.out.println("Thread: " + Thread.currentThread().getId() + " is reading a string: " + str);
                Thread.sleep(1500);
                System.out.println("Thread: " + Thread.currentThread().getId() + " has stopped reading");
                
                lock.lock();
                readActive.getAndDecrement();
                // 没有活跃读者时唤醒写者
                if (readActive.get() == 0 ) {
                    write.signalAll();
                } 
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }

    static class WriterThread extends Thread {
        @Override
        public void run() {
            try {
                queue.lock();
                lock.lock();
                writeWait.getAndIncrement();
                queue.unlock();
                
                // 有活跃读者或写者时阻塞
                while(readActive.get() > 0 ||  writeActive.get() > 0)   
                    write.await();
                writeWait.getAndDecrement();
                writeActive.getAndIncrement();
                lock.unlock();
                
                // 模拟写操作
                System.out.println("Thread: " + Thread.currentThread().getId() + " is writing");
                str.append(val);
                val++;
                Thread.sleep(2000);
                System.out.println("Thread: " + Thread.currentThread().getId() + " has stopped writing");
                
                lock.lock();
                writeActive.getAndDecrement();
                // 优先唤醒等待的写者,没有则唤醒读者
                if(writeWait.get() > 0) {
                    write.signalAll();
                } else {
                    read.signalAll();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者krysznys

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.20 17:06:04