Java 监视器而不是二进制信号量
Posted
技术标签:
【中文标题】Java 监视器而不是二进制信号量【英文标题】:Java monitor instead of binary semaphore 【发布时间】:2013-09-18 13:34:17 【问题描述】:我正在做一个学校作业,我应该使用监视器同步两个线程。在这种情况下,每台监视器都控制一条铁路的通行,而火车需要锁定那条铁路,以便其他人无法访问它或必须等到那条铁轨空闲。我以前从未使用过显示器,所以我确信问题在于我对显示器工作原理的了解有限。火车和它们的线程本身工作得很好,我已经在同一代码中成功地使用了二进制信号量。现在我正在尝试用监视器替换信号量。
我基本上想知道条件和锁是如何工作的。我在不同的博客和论坛上阅读过,但似乎无法理解这个概念。
重要提示:我不允许使用synchronized
关键字。
当我运行当前代码时,我收到以下错误。错误发生在leave
方法中的occupied.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();
我将非常感谢任何关于错误的帮助和/或想法。
谢谢!
【问题讨论】:
在leave()
中,将lock.unlock()
移到最后一行。
【参考方案1】:
你的锁定太粗了。作为一般模式,除非您有非常特殊的情况,否则所有锁定都应采用以下形式:
lock.lock();
try
....
finally
lock.unlock();
您没有使用此模式(甚至以不同的方法锁定和解锁)。
从技术上讲,您的问题是当您没有拿着 lock
监视器时,您正在发出 occupied
条件的信号。
在您的程序中,轨道部分的“独占”锁定不应该是实际的 Java 锁定机制,而是布尔变量 isOccupied
。更改您的代码,以便这两种方法执行正确的 try...finally 块,并且您可能应该将 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();
【讨论】:
【参考方案2】:您不必实现自己的监视器。锁定是监视器:
public class Monitor
private final Lock lock = new ReentrantLock();
private int id;
public Monitor(int id)
super();
this.id = id;
public void enter()
lock.lock();
public boolean tryEnter()
return lock.tryLock();
public void leave()
lock.unlock();
【讨论】:
以上是关于Java 监视器而不是二进制信号量的主要内容,如果未能解决你的问题,请参考以下文章