我可以用两个对象作为 Java 中的锁来实现阻塞队列吗?

Can I implement blocking queue with two objects serving as locks in Java?

我试图通过实现阻塞队列 class 来理解 Java 的同步关键字 wait() 和 notify()。 this 文章描述了一种阻塞队列实现。但是我想知道是否可以使用两个对象作为锁来实现阻塞队列?下面的代码正确吗?

public class BlockingQueue {
  private List<Object> queue = new LinkedList<Object>();
  private int limit;
  private Object slots = new Object();
  private Object objs = new Object();
  public BlockingQueue(int limit) {
    this.limit = limit;
  }
  private synchronized void enqueue(Object o) 
  throws InterruptedException {
    if (queue.size() == limit)
      slots.wait();
    objs.notify();
    queue.add(o);
  }
  private synchronized Object dequeue()
  throws InterruptedException {
    if (queue.size() == 0)
      objs.wait();
    slots.notify();
    return queue.remove(0);
  }
}

首先,您不能在未同步的对象上等待或通知。在这里你会使用 this.wait() 和 this.notifyAll.

其次,你不应该在没有重新检查你的情况的情况下只等待一次。无论你在 'if' 中放入什么,都应该在一个 while 循环中;那是因为您可能会在条件未更改的情况下错误地收到通知,尤其是因为您在实例上使用监视器,任何外部人员都可以在该实例上进行同步和通知。您应该使用 synchronized(privatelockobject) {}。

这引出了您的问题,您能否同步 2 个以上的对象...是的,通过嵌套同步块,但这会导致代码挂起,因为 wait() 调用仅释放您等待的一个监视器,不是外部显示器。因此,这是毫无意义的。

如果你试图避免通知等待队列的读者和作者,这是一个光荣的想法,但你不能用 synchronized 做到这一点。引用的示例是使用单个监视器执行的,这也是为什么它必须使用 notifyAll() 而不是 notify() 的原因,因为您要确保唤醒等待的正确线程。通常你必须在 2 个不同的条件下使用 ReentrantLock(不是空的,也不是满的)。