我可以在Java中使用Semaphore实现阻塞队列吗?

我想知道是否可以使用Semaphore来实现阻塞队列?

在下面的代码中,我使用一个信号量来保护关键部分,并使用另外两个信号量对象来跟踪空槽和填充对象的数量。

public class BlockingQueue { private List queue = new LinkedList(); private int limit; private Semaphore slots; // semaphore for empty slots private Semaphore objs; // semaphore for filled slots private Semaphore mutex; // for the critical section public BlockingQueue(int limit) { this.limit = limit; this.slots = new Semaphore(limit); // initial empty slot = capacity this.objs = new Semaphore(0); this.mutex = new Semaphore(1); } private void enqueue(Object o) throws InterruptedException { slots.acquire(); mutex.acquire(); // critical section starts queue.add(o); mutex.release(); // critical section ends objs.release(); } private Object dequeue() throws InterruptedException { objs.acquire(); mutex.acquire(); // critical section starts Object o = queue.remove(0); mutex.release(); // critical section ends slots.release(); return o; } } 

添加到先前的注释 – 我们可以同意您的代码有效(这是一个众所周知的算法),特别是您在保护LinkedList方面是正确的,因为它不是内部线程安全的。

但是,如果您将代码与java util实现进行比较http://grepcode.com/file_/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/concurrent/ArrayBlockingQueue.java/ ?v =来源可能会提出一些要考虑的要点:

  1. 请谷歌讨论“ReentrantLock与Binary Semaphore”:它们都创建了一个互斥锁并保护了一个关键部分 ,但前者更好地描述了你的意图,而且它可能更容易进行未来的维护。 例如,同事程序员不能通过未获取它的线程意外释放ReentrantLock

  2. 谷歌讨论“信号量与条件变量”:两者都允许你“等待某些东西变得可用”,但条件变量可能更通用,而且你可以将所有条件绑定到一个锁(如java util代码那样) )。 我认为这对性能有一些小的影响,加上你需要处理未来需求的方式,如中断 ,超时,崩溃。 这不会使您的代码“错误”,这只是您需要考虑的事情。

没有测试,我会说这是有效的。 但是,每个release()都会通知在acquire()中阻塞的线程。 所以你真的至少有与reentrantlock +条件相同的成本,可能更糟糕,因为有2个acquire和2个release()调用。