Reader java 中的编写器实现

Reader Writer implementation in java

我正在尝试使用通知和等待实现一个 reader-writer。但我想我被困住了。 我的顺序是这样的。 RRRRRRRRRRWWWWWWWWW 如果主程序以 reader 首先调用,就会发生这种情况。 要么 WWWWWWWRRRRRRRRRRR。如果主程序首先调用编写器,就会发生这种情况。 看起来读取通知根本不起作用。编写器线程永远不会执行。

如果我在 运行 方法中使 while 循环变为 运行 无限那么它只是 RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR........。作家没有机会写作。 你能看看这个吗?

数据CLASS

public class Data {
    private int q ;
    private boolean isAnyOneReading;

    public Data() {
    }

    public  void readQ() {
        synchronized (this){
            isAnyOneReading = true;
            System.out.println("Read start "+q);
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        synchronized (this){
            isAnyOneReading = false;
            System.out.println("Read end "+q);
            notifyAll();
        }
    }

    public synchronized void writeQ(int q) {
        System.out.println(isAnyOneReading);
        while (isAnyOneReading){
            try{
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("Done");
                Thread.currentThread().interrupt();
            }
        }
        System.out.println("Write start "+q);
        this.q = q;
        try{
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
            Thread.currentThread().interrupt();
        }
        System.out.println("Write end "+q);
        notifyAll();
    }
}

READER CLASS

public class Reader implements  Runnable {
    private Data data;
    private Thread readerThread;


    public Reader(Data data) {
        this.data = data;
        readerThread = new Thread(this, "ReaderThread");
    }


    void startThread(){
        readerThread.start();
    }

    @Override
    public void run() {
        int i = 0 ;
        while (i != 5){
            data.readQ();
            i++;
        }
    }
}

作者CLASS

public class Writer  implements  Runnable{
    private Data data;
    private Thread writerThread;

    public Writer(Data data) {
        this.data = data;
        writerThread = new Thread(this,"WriterThread," );
    }

    void startThread(){
        writerThread.start();
    }

    @Override
    public void run() {
        int i = 0 ;
        int j = 0 ;
        while (j != 5){
            data.writeQ(i++);
           // i++;
           j++;
        }
    }
}

主要CLASS

public class ReaderWriterDemo {
    public static void main(String[] args) {
        Data data = new Data();
        Reader reader = new Reader(data);
        Writer writer = new Writer(data);

        reader.startThread();
        writer.startThread();



    }
}

尝试从数据 class 中删除 Thread.sleep。 并像这样在 运行 方法中添加 Thread.sleep 。 (粘贴一个示例):

 @Override
public void run() {
    int i = 0;
    while (i != 5) {
        data.readQ();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            i++;
        }
    }
}

Read 的 notifyAll() 有效,但似乎 read() 再次被调用并在 write() 中的任何其他操作之前更改 isAnyOneReading 的值。这就是检查失败并且 write() 再次开始等待的原因。正如 Danny Fried 建议的那样,将 Thread.sleep() 移动到 运行 方法会有所帮助。

看起来像一个简单的饥饿案例。考虑您的作者的主循环:

    while (j != 5){
        data.writeQ(i++);
       // i++;
       j++;
    }

data.writeQ() 是一个 synchronized 方法:它在 returns 之前做的最后一件事是解锁锁。它在下一次调用时做的第一件事就是重新锁定锁。中间没有发生太多事情——递增和测试一个局部变量就够了。

Java synchronized 锁不 公平 。 (即,当锁可用时,系统 而不是 保证获胜者将是等待时间最长的线程。)事实上,它可能是 相反的公平:OS可能会尝试通过始终选择最容易唤醒的线程来最大化CPU(s)的有效使用。

当作者在每次后续迭代中返回调用 data.writeQ() 时,可能 OS 甚至还没有 started 唤醒reader,它只是让作者再次输入 synchronized 块。


您的 reader 也会发生同样的事情。代码有点复杂,但就像在 writer 中一样,data.readQ() 在返回之前做的最后一件事是解锁锁,而在下一次调用时它做的第一件事就是锁定它再次.


暴力破解:用fair ReentrantLock object.

替换synchronized

替代解决方案,这对于实际运行的程序而言更为典型:让线程在两者之间做 其他事情(例如,让它们做一些 I/O)调用锁定的函数,从而让其他线程有机会进入并使用锁定的资源。