0

新しい条件を作成chopstickFreeし、pickUpChopstick()メソッドでロックを待っていますが、まったくアクセスできません。

デバッグを通じて、メソッドのchopstickFree.await()行に到達すると、無期限に一時停止することがわかりましたpickUpChopstick()

理解できない?コンストラクターのそのコードは、それを機能させるための不確かな試みでしたが、いずれにせよ、新しい条件を作成し、それが解放されていることをすべての人に通知しましたが、まったくロックできませんか?

public class Chopstick {
    Lock lock = new ReentrantLock();

    private Condition chopstickFree = lock.newCondition();
    private Condition chopstickInUse = lock.newCondition();

    Chopstick() {
        lock.lock();
        chopstickFree.signalAll();
        lock.unlock();
    }

    // Pick up chopstick
    public void pickUpChopstick() throws InterruptedException {
        lock.lock();

        try {
            chopstickFree.await(); // ALWAYS PAUSES HERE INDEFINITELY
            chopstickInUse.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    // Release chopstick
    public void releaseChopstick() {
        lock.lock();
        chopstickFree.signal();
        lock.unlock();
    }
}

何か案は?

乾杯

4

1 に答える 1

2

Condition#signalAll()現在存在するスレッドCondition#await()(またはそのフレンド) にのみシグナルを送信します。つまり、シグナルは後の呼び出しのためにキューに入れられません。

正しく実装するには、ロックによって保護された別のフラグが必要です。

public class Chopstick {
  private final Lock lock = new ReentrantLock();
  private final Condition chopstickFree = lock.newCondition();
  private volatile boolean isFree = true;

  Chopstick() { /* Nothing */ }

  // Pick up chopstick
  public void pickUpChopstick() throws InterruptedException {
    lock.lock();

    try {
      while (!isFree) {
        chopstickFree.await();
      }
      isFree = false;
    } finally {
      lock.unlock();
    }
  }

  // Release chopstick
  public void releaseChopstick() {
    lock.lock();
    try {
      isFree = true;
      chopstickFree.signal();
    } finally {
      lock.unlock();
    }
  }
}

Semaphoreこれは、元の実装に意図的に少し近い を使用したバージョンです。

public class Chopstick {
  private final Semaphore chopsticksAvailable = new Semaphore(1);

  Chopstick() {
    // Nothing
  }

  // Pick up chopstick
  public void pickUpChopstick() throws InterruptedException {
    chopsticksAvailable.acquire();
  }

  // Release chopstick
  public void releaseChopstick() {
    chopsticksAvailable.release();
  }
}
于 2013-04-14T22:27:01.110 に答える