我正在做一项学校作业,我应该使用监视器同步两个线程。在这种情况下,每个监视器控制一段铁路的访问,并且火车需要锁定该段铁路,以便其他监视器无法访问它或必须等待直到该段轨道空闲。我以前从未使用过显示器,所以我确信问题在于我对显示器工作原理的了解有限。火车及其线程本身工作得很好,我已经在相同的代码中成功地使用了二进制信号量。现在我正在尝试用监视器替换信号量。
我基本上想知道条件和锁到底是如何工作的。我读过不同的博客和论坛,但似乎无法理解这个概念。
重要说明:我不允许使用 synchronized
关键字。
当我运行当前代码时,出现以下错误。错误发生在 leave
方法中的 ocpied.signal()
处:
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.signalAll(AbstractQueuedSynchronizer.java:1956)
这是到目前为止的代码:
public class Monitor {
private final Lock lock = new ReentrantLock();
private final Condition occupied = lock.newCondition();
private boolean isOccupied = false;
private int id;
public Monitor(int id) {
super();
this.id = id;
}
public void enter(){
lock.lock();
try {
if(isOccupied)
occupied.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
isOccupied = true;
}
public boolean tryEnter(){
if(isOccupied){
return false;
}else{
enter();
return true;
}
}
public void leave(){
lock.unlock();
isOccupied = false;
occupied.signal();
}
}
如果有任何帮助和/或关于问题的想法,我将不胜感激。
谢谢!
最佳答案
你的锁定太粗略了。作为一般模式,除非有非常特殊的情况,否则所有锁定都应采用以下形式:
lock.lock();
try {
....
} finally {
lock.unlock();
}
您没有使用此模式(甚至以不同的方法锁定和解锁)。
从技术上讲,您的问题是当您没有持有lock
监视器时,您正在发出占用
状态信号。
在您的程序中,轨道部分上的“独占”锁不应是实际的 Java 锁机制,而是 boolean 变量 isOccupied
。更改您的代码,以便这两个方法执行正确的 try...finally block ,而且,您应该将您的 Condition 重命名为“未占用”,并反转保留它的逻辑。
public void enter(){
lock.lock();
try {
while(isOccupied)
unoccupied.await();
isOccupied = true;
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void leave(){
lock.lock();
try {
isOccupied = false;
unoccupied.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
关于Java 监视器代替二进制信号量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18873686/