【问题标题】:Java monitor instead of binary semaphoreJava 监视器而不是二进制信号量
【发布时间】: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()移到最后一行。

标签: java multithreading concurrency locking monitoring


【解决方案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();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-23
      • 1970-01-01
      • 2015-07-03
      • 1970-01-01
      • 1970-01-01
      • 2012-10-07
      • 1970-01-01
      相关资源
      最近更新 更多