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

时间:2016-02-03 04:54:18

标签: java mutex semaphore blockingqueue

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

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

public class BlockingQueue {
  private List<Object> queue = new LinkedList<Object>();
  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;
  }
}

3 个答案:

答案 0 :(得分:2)

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

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

  1. Google请讨论“ReentrantLock与Binary Semaphore”:他们都创建了互斥锁&amp;保护关键部分,但前者更好地描述了您的意图,而且可能更容易进行日常维护。例如,同事程序员不能通过没有获取它的线程意外释放ReentrantLock

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

答案 1 :(得分:1)

如果没有测试,我会说这很有效。 但是,每个release()都会通知在acquire()中阻塞的线程。因此,您实际上至少具有与重入锁定+条件相同的成本,可能更糟糕,因为有2个获取和2个release()调用。

答案 2 :(得分:0)

信号量是另一种实现互斥和同步的方式。 二进制信号量或互斥锁可用于锁定和解锁临界区。 通用信号量或计数信号量可用于跟踪空闲槽位和占用槽位。