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

Reader-Writer多线程实现问题:Writer线程无法穿插Reader执行

读写者问题代码分析:Writer线程无法穿插执行的原因

问题描述

我是多线程开发新手,正在尝试解决读写者(Reader-Writer)问题,编写了如下Java代码,但运行时所有Reader线程先执行完毕,Writer线程只能最后执行,无法穿插在Reader线程之间。

代码实现

public class ReaderWriterProblem implements Runnable {
    Semaphore readerSemaphore;
    Semaphore writerSemaphore;
    static int currentReadingThreads = 0;

    public ReaderWriterProblem(Semaphore readerSemaphore, Semaphore writerSemaphore) {
        this.readerSemaphore = readerSemaphore;
        this.writerSemaphore = writerSemaphore;
    }

    public void enterCriticalSection() throws InterruptedException {
        if(!Thread.currentThread().getName().startsWith("Reader")) {
            writerSemaphore.acquire();
            
            System.out.println(Thread.currentThread().getName()+" acquired lock");
            Thread.sleep(1000);
            
            System.out.println(Thread.currentThread().getName()+" going to release lock");
            readerSemaphore.release();
            writerSemaphore.release();
        }
        
        if(Thread.currentThread().getName().startsWith("Reader")) {
            if(currentReadingThreads == 0)
                readerSemaphore.acquire();
            
            currentReadingThreads = currentReadingThreads + 1;
            
            System.out.println(Thread.currentThread().getName()+" in critical section");
            Thread.sleep(1000);
            
            System.out.println(Thread.currentThread().getName()+" going to leave critical section");
            currentReadingThreads = currentReadingThreads - 1;

            if(currentReadingThreads == 0) {
                readerSemaphore.release();
                writerSemaphore.release();
            }
        }
    }

    @Override
    public void run() {
        try {
            enterCriticalSection();
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String args[]) {
        Semaphore readerSemaphore = new Semaphore(1);
        Semaphore writerSemaphore = new Semaphore(0);
        
        int readerThreadCounter = 0, writerThreadCounter = 0;
        
        for(int i = 0; i < 10; i++) {
            Thread readerThread1 = new Thread(new ReaderWriterProblem(readerSemaphore, writerSemaphore), "Reader Thread "+readerThreadCounter);
            readerThreadCounter = readerThreadCounter + 1;

            Thread readerThread2 = new Thread(new ReaderWriterProblem(readerSemaphore, writerSemaphore), "Reader Thread "+readerThreadCounter);
            readerThreadCounter = readerThreadCounter + 1;

            Thread writerThread1 = new Thread(new ReaderWriterProblem(readerSemaphore, writerSemaphore), "Writer Thread "+readerThreadCounter);
            readerThreadCounter = readerThreadCounter + 1;

            Thread writerThread2 = new Thread(new ReaderWriterProblem(readerSemaphore, writerSemaphore), "Writer Thread "+readerThreadCounter);
            readerThreadCounter = readerThreadCounter + 1;

            Thread readerThread3 = new Thread(new ReaderWriterProblem(readerSemaphore, writerSemaphore), "Reader Thread "+readerThreadCounter);
            readerThreadCounter = readerThreadCounter + 1;
            
            readerThread1.start();
            readerThread2.start();
            writerThread1.start();
            writerThread2.start();
            readerThread3.start();
        }
    }
}

运行输出

Reader Thread 0 in critical section
Reader Thread 6 in critical section
.
.
.
Reader Thread 0 going to leave critical section
Reader Thread 6 going to leave critical section
.
.
.
Writer Thread 0 acquired lock
Writer Thread 0 going to release lock
Writer Thread 1 acquired lock
Writer Thread 1 going to release lock
.
.
.
Writer Thread 19 acquired lock
Writer Thread 19 going to release lock

问题原因分析

1. 信号量初始化逻辑错误

writerSemaphore初始化为Semaphore(0),意味着这个信号量一开始没有可用许可。Writer线程启动后执行writerSemaphore.acquire()会直接进入阻塞状态,完全没有机会参与锁竞争。只有当最后一个Reader线程执行完毕时,才会释放一次writerSemaphore,此时才会唤醒一个Writer线程,但后续Writer仍需等待,而Reader线程会持续抢占readerSemaphore,导致所有Reader先执行完毕。

2. 读写互斥的核心逻辑完全混乱

  • Writer线程的释放逻辑错误:Writer获取writerSemaphore后,执行完毕同时释放readerSemaphore和writerSemaphore,这会导致readerSemaphore的许可数异常增加,彻底破坏了信号量的互斥控制逻辑。
  • 读者计数的线程安全问题:静态变量currentReadingThreads没有任何同步保护(如synchronized或原子类),多个Reader线程同时修改这个变量会导致计数不准确,进而引发锁的释放时机错误。
  • 读者进入的非原子操作:Reader线程中if(currentReadingThreads == 0) readerSemaphore.acquire()的判断与锁获取操作不是原子的,可能出现多个Reader线程同时判断currentReadingThreads == 0,然后都去获取readerSemaphore,破坏了互斥性。
  • 信号量依赖关系错误:正常读写者问题中,应该用一个互斥锁保护读者计数,用另一个信号量控制写者访问,而你代码中的两个信号量互相依赖的逻辑完全不符合读写锁的设计思路。

修正方向

  • 最简单可靠的方式是直接使用Java自带的ReentrantReadWriteLock,它已经实现了成熟的读写锁逻辑,无需手动管理信号量和计数。
  • 如果坚持手动用信号量实现:
    • 新增一个互斥信号量(如mutex),用于保护currentReadingThreads的修改和判断操作,确保这些操作是原子的。
    • 用writeLock信号量控制写者的访问:第一个Reader进入时获取writeLock,最后一个Reader离开时释放writeLock;写者必须获取writeLock才能进入临界区,确保读写互斥。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 02:27:06