2

私は、モニターを使用して 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。コードを変更して、2 つのメソッドが正しい try...finally ブロックを実行するようにします。また、条件の名前を「占有されていない」に変更し、それを保持するロジックを逆にする必要があります。

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 に答える