【问题标题】:Readers-writers with monitors - java带监视器的读写器 - java
【发布时间】:2015-09-29 07:16:58
【问题描述】:

我正在用 Java 中的监视器实现读写器问题。有很多读者和作家。当一个作家正在写作时,没有其他读者或作家可以阅读或写作。 许多读者可以同时阅读。 我不知道这段代码有什么问题。 有死锁问题。

class Monitor {
    private int readers; // specifies number of readers reading
    private boolean writing; // specifies if someone is writing
    private Condition OK_to_Read, OK_to_Write;

    public Monitor() {
        readers = 0;
        writing = false;
        OK_to_Read = new Condition();
        OK_to_Write = new Condition();
    }

    public synchronized void Start_Read(int n) {

        System.out.println("wants to read " + n);
        if (writing || OK_to_Write.is_non_empty()) {
            try {
                System.out.println("reader is waiting " + n);
                OK_to_Read.wait_();
            } catch (InterruptedException e) {
            }
        }
        readers += 1;
        OK_to_Read.release_all();

    }

    public synchronized void End_Read(int n) {

        System.out.println("finished reading " + n);
        readers -= 1;

        if (OK_to_Write.is_non_empty()) {
            OK_to_Write.release_one();
        } else if (OK_to_Read.is_non_empty()) {
            OK_to_Read.release_one();
        } else {
            OK_to_Write.release_all();
        }

    }

    public synchronized void Start_Write(int n) {
        System.out.println("wants to write " + n);
        if (readers != 0 || writing) {
            try {
                System.out.println("Writer is waiting " + n);
                OK_to_Write.wait_();
            } catch (InterruptedException e) {
            }
        }

        writing = true;

    }

    public synchronized void End_Write(int n) {

        System.out.println("finished writing " + n);
        writing = false;
        if (OK_to_Read.is_non_empty()) {
            OK_to_Read.release_one();
        } else if (OK_to_Write.is_non_empty()) {
            OK_to_Write.release_one();
        } else {
            OK_to_Read.release_all();
        }

    }

}

class Condition {
    private int number;// specifies the number of readers/writers waiting

    public Condition() {
        number = 0;
    }

    public synchronized boolean is_non_empty() {
        if (number == 0)
            return false;
        else
            return true;
    }

    public synchronized void release_all() {
        number = 0;
        notifyAll();
    }

    public synchronized void release_one() {
        number -= 1;
        notify();
    }

    public synchronized void wait_() throws InterruptedException {
        number++;
        wait();
    }

}

class Reader extends Thread {
    private Monitor M;
    private String value;

    public Reader(String name, Monitor c) {
        super(name);
        M = c;
    }

    public void run() {
        for (int i = 0; i < 10; i++) {
            M.Start_Read(i);
            // System.out.println("Reader "+getName()+" is retreiving data...");
            System.out.println("Reader is reading " + i);
            M.End_Read(i);
        }

    }
}

class Writer extends Thread {
    private Monitor M;
    private int value;

    public Writer(String name, Monitor d) {
        super(name);
        M = d;
    }

    public void run() {
        for (int j = 0; j < 10; j++) {
            M.Start_Write(j);
            // System.out.println("Writer "+getName()+" is writing data...");
            System.out.println("Writer is writing " + j);
            M.End_Write(j);
        }

    }
}

class mainClass {
    public static void main(String[] args) {
        Monitor M = new Monitor();
        Reader reader = new Reader("1", M);
        Writer writer = new Writer("1", M);
        writer.start();
        reader.start();
    }
}

【问题讨论】:

  • 根据您的代码,您正在为每个读者和作者创建一个线程。我建议您阅读此qs,因为它可能也适用于您的情况。

标签: java concurrent-programming monitors


【解决方案1】:

问题其实很简单:你所有的Start_WriteEnd_WriteStart_ReadEnd_Read方法都标记为synchronized。您的程序中只有一个 Monitor 实例。将synchronized 视为默认附加到每个java 对象的排他锁。一次只能有一个线程在属于该对象的任何同步方法中运行。只有在方法返回时才会释放锁。

考虑以下事件顺序:

1. Writer enters Start_Write, and takes the lock on Monitor
2. Writer exits Start_Write, and releases the lock on Monitor
3. Reader enters Start_Read, and takes the lock on Monitor
4. Reader cannot exit Start_Read, because the writer is still writing.
   The lock on Monitor IS NOT RELEASED
5. Writer wants to enter End_Write, but the lock is not available because
   Reader is still holding it

这是你的僵局。

  • Reader 不能在不退出 Start_Read 的情况下释放锁
  • 要退出 Start_Read,它会等待 Writer 调用 End_Write
  • Writer 无法调用 End_Write,因为它需要锁才能这样做

您的问题的解决方案非常简单:删除所有这些自定义逻辑并使用 JDK 提供的ReentrantReadWriteLock,它专门用于处理您的问题。

ReetrantReadWriteLock.readLock().lock() 等价于Monitor.Start_Read() ReetrantReadWriteLock.readLock().unlock() 等价于 Monitor.End_Read() ReetrantReadWriteLock.writeLock().lock() 等价于 Monitor.Start_Write() ReetrantReadWriteLock.writeLock().unlock() 等价于Monitor.End_Write()

还有一条评论:您应该始终将释放锁的代码放入finally 块中,以确保在抛出异常时您的应用程序不会陷入死锁。例如:

class Writer extends Thread {
    private ReentrantReadWriteLock lock;
    private int value;

    public Writer(String name, ReentrantReadWriteLock lock) {
        super(name);
        this.lock = lock;
    }

    public void run() {
        for (int j = 0; j < 10; j++) {
            lock.writeLock().lock();
            try{
                // System.out.println("Writer "+getName()+" is writing data...");
                System.out.println("Writer is writing " + j);
            } finally {
                lock.writeLock().unlock();
            }
        }

    }
}

【讨论】:

    【解决方案2】:

    我已将sleep 方法放入您的代码中。请检查并尝试。

    class Monitor
    {
    private volatile int readers; //specifies number of readers reading
    private volatile boolean writing; //specifies if someone is writing
    private volatile Condition OK_to_Read, OK_to_Write;
    
     public Monitor()
    {
        readers = 0;
        writing = false;
        OK_to_Read = new Condition();
        OK_to_Write = new Condition();
    }
    
    public synchronized void Start_Read(int n)
    {
    
         System.out.println("wants to read " + n);
        if(writing || OK_to_Write.is_non_empty())
        {
            try{
                System.out.println("reader is waiting " + n);
                OK_to_Read.sleep_();
            }
            catch(InterruptedException e){}
        }
        readers += 1;
        OK_to_Read.release_all();
    
    }
    
    public synchronized void End_Read(int n)
    {
    
            System.out.println("finished reading " + n);
            readers -= 1;
    
            if(OK_to_Write.is_non_empty())
            {
                OK_to_Write.release_one();
            }
            else if(OK_to_Read.is_non_empty())
            {
                OK_to_Read.release_one();
            }
            else
            {
                OK_to_Write.release_all();
            }
    
    }
    
    public synchronized void Start_Write(int n)
    {
        System.out.println("wants to write " + n);
        if(readers != 0 || writing)
        {
            try{
                System.out.println("Writer is waiting " + n);
                OK_to_Write.sleep_();
                    }catch(InterruptedException e){}
        }
    
        writing = true;
    
    }
    
    public synchronized void End_Write(int n)
    {
    
        System.out.println("finished writing " + n);
        writing = false;
        if(OK_to_Read.is_non_empty())
        {
            OK_to_Read.release_one();
        }
        else if(OK_to_Write.is_non_empty())
        {
            OK_to_Write.release_one();
        }
        else
        {
            OK_to_Read.release_all();
        }
    
    }
    
    }
    
    class Condition
    {
    private int number;//specifies the number of readers/writers waiting
    
    public Condition()
    { 
        number = 0; 
    }
    
    public synchronized boolean is_non_empty()  
    { 
        if(number == 0)
            return false; 
        else
            return true;
    }
    
    public synchronized void release_all()
    { 
    number = 0;
    notifyAll(); 
    }
    
    
    public synchronized void release_one()
    { 
    number -=1;
    notify(); 
    }   
    
    public synchronized void wait_() throws InterruptedException
    {  
        number++;
        wait();
    }
    public synchronized void sleep_() throws InterruptedException
    {  
        Thread.sleep(1000);
    }
    
    }
    
    
    class Reader extends Thread
    {
    private Monitor M;
    private String value;
    public Reader(String name,Monitor c)
    {
        super(name);
        M=c;
    }
    
    public void run()
    {
        for(int i = 0; i < 10; i++){
                M.Start_Read(i);
                //System.out.println("Reader "+getName()+" is retreiving data...");
                System.out.println("Reader is reading " + i);
                M.End_Read(i);
        }
    
    }
    }
    
    class Writer extends Thread
    {
    private Monitor M;
    private int value;
    public Writer(String name, Monitor d)
    {
        super(name);
        M = d;
    }
    
    public void run()
    {
        for(int j = 0; j < 10; j++){
                M.Start_Write(j);
                //System.out.println("Writer "+getName()+" is writing data...");
                System.out.println("Writer is writing " + j);
                M.End_Write(j);
        }
    
    }
    }
    
    public class Demo
    {
    public static void main(String [] args)
    {
        Monitor M = new Monitor();
        Reader reader = new Reader("1",M);
        Writer writer = new Writer("1",M);
        writer.start();
        reader.start();     
    } }
    

    【讨论】:

    • 我已经使用睡眠和等待来完成它......但问题是可能会出现读者和作者都在做他们的工作的情况,这是错误的。一次只有一个人可以工作。
    【解决方案3】:

    您应该为 wait() 函数设置一个值。

    等待 10 秒:

    public synchronized void wait_() throws InterruptedException {
            number++;
            wait(10000);
        }
    

    对我来说,修改后效果很好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-31
      • 1970-01-01
      相关资源
      最近更新 更多