2

我正在做一个学校作业,我应该使用监视器同步两个线程。在这种情况下,每台监视器都控制着一条铁路的通行,而火车需要锁定那条铁路,以便其他人无法访问它或必须等到那条铁轨空闲。我以前从未使用过显示器,所以我确信问题在于我对显示器工作原理的了解有限。火车和它们的线程本身工作得很好,我已经在同一代码中成功地使用了二进制信号量。现在我正在尝试用监视器替换信号量。

我基本上想知道条件和锁是如何工作的。我在不同的博客和论坛上阅读过,但似乎无法理解这个概念。

重要提示:我不允许使用synchronized关键字。

当我运行当前代码时,出现以下错误。错误发生在occupied.signal()方法中leave

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();
}

}

我将非常感谢任何有关错误的帮助和/或想法。

谢谢!

4

2 回答 2

2

你的锁定太粗糙了。作为一般模式,除非您有非常特殊的情况,否则所有锁定都应采用以下形式:

lock.lock();
try {
    ....
} finally {
     lock.unlock();
}

您没有使用此模式(甚至以不同的方法锁定和解锁)。

从技术上讲,您的问题是occupied您在不拿着lock显示器时发出信号。

在您的程序中,轨道部分的“独占”锁不应该是实际的 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();
    }
}
于 2013-09-18T13:45:22.317 回答
0

您不必实现自己的监视器。锁定是监视器:

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();
    }
}
于 2013-09-18T14:08:30.703 回答