当前位置: 首页 > 面试题库 >

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

华永新
2023-03-14
问题内容

我想知道是否可以使用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;
  }
}

问题答案:

在前面的评论中添加内容-我们可以同意您的代码有效(这是一种众所周知的算法),尤其是您在保护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”的讨论:它们都创建了互斥体并保护了 关键部分 ,但是前者可以更好地描述您的意图,并且将来可能更容易维护。例如,同一个程序员不能通过未被获取的线程意外释放ReentrantLock

  2. Google讨论“信号量与条件变量”:两者都允许您“等待某些东西变为可用”,但是条件变量可能更通用,此外,您还可以将所有条件绑定到一个锁(如Java util代码那样) )。我认为这对性能有轻微的影响,另外还有满足未来需求(例如 中断 ,超时,崩溃)的方式。这不会使您的代码“错误”,只是您需要考虑的事情。



 类似资料:
  • 2)Java的内置使用了两个锁:takeLock和putLock,并分别用在put()和take()中,我看到间隔队列是一个链表,不是线程安全的,那怎么行呢?

  • 本文向大家介绍详解Java阻塞队列(BlockingQueue)的实现原理,包括了详解Java阻塞队列(BlockingQueue)的实现原理的使用技巧和注意事项,需要的朋友参考一下 阻塞队列 (BlockingQueue)是Java util.concurrent包下重要的数据结构,BlockingQueue提供了线程安全的队列访问方式:当阻塞队列进行插入数据时,如果队列已满,线程将会阻塞等待直

  • 3. 阻塞信号 3.1. 信号在内核中的表示 以上我们讨论了信号产生(Generation)的各种原因,而实际执行信号的处理动作称为信号递达(Delivery),信号从产生到递达之间的状态,称为信号未决(Pending)。进程可以选择阻塞(Block)某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽

  • 阻塞信号是保持该信号并推迟发送,直到阻塞解除,但不会丢失。 结构体sigset_t(信号集合) 其中每一位对应系统支持的一种信号。结构体内部是数组。 函数 函数名 描述 [[sigemptyset sigempty]] 初始化信号集为空集 [[sigfillset sigfillset]] 初始化信号集包含全部信号 [[sigaddset sigaddset]] 向信号集中添加信号 [[sigde

  • 问题内容: 我有一个经典的问题,线程将事件推送到第二个线程的传入队列。仅这次,我对性能非常感兴趣。我要实现的是: 我想要并发访问队列,生产者推送,接收者弹出。 当队列为空时,我希望消费者阻止队列,等待生产者。 我的第一个想法是使用,但是我很快意识到它不是并发的,并且会降低性能。另一方面,我现在使用,但仍要为每个出版物支付/ 的费用。由于使用者在找到空队列时不会阻塞,因此我必须进行同步并处于锁定状态

  • 问题内容: 我在一个非常简单的生产者-消费者场景中使用 java.util.concurrent.BlockingQueue 。例如,此伪代码描述了使用者部分: 到目前为止,一切都很好。在阻塞队列的javadoc中,我读到: BlockingQueue本质上不支持任何类型的“关闭”或“关闭”操作,以指示将不再添加任何项目。这些功能的需求和使用往往取决于实现。例如,一种常见的策略是让生产者插入特殊的