我正在用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();
}
}
答案 0 :(得分:2)
问题实际上很简单:您的所有Start_Write
,End_Write
,Start_Read
,End_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
有您的僵局。
解决问题的方法非常简单:删除所有这些自定义逻辑,并使用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();
}
}
}
}
答案 1 :(得分:0)
我已将sleep
方法放入您的代码中。请检查此&amp;尝试。
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();
} }
答案 2 :(得分:0)
你应该得到wait()函数的值。
等待10秒钟:
public synchronized void wait_() throws InterruptedException {
number++;
wait(10000);
}
对我来说,修改后它可以正常工作。