Java - Reentrant Lock,无法访问新创建的Condition

时间:2013-04-14 21:07:16

标签: java concurrency locking conditional-statements reentrantlock

我已经创建了一个新的条件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();
    }
}

有什么想法吗?

干杯

1 个答案:

答案 0 :(得分: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();
  }
}