Java中的LinkedBlockingQueue
Java中的LinkedBlockingQueue是BlockingQueue接口的实现,并且是java.util.concurrent包的一部分。 LinkedBlockingQueue具有ArrayBlockingQueue和DelayQueue的功能。 ArrayBlockingQueue是一个有界阻塞队列,其中,DelayQueue是一个无界阻塞队列。 LinkedBlockingQueue位于中间,因为它是一个可选绑定的阻塞队列,这意味着可以指定队列的容量,从而使其成为有界的,也可以不指定。
Java中的LinkedBlockingQueue
LinkedBlockingQueue基于链接的节点,其中每个节点都保留对下一个节点的引用。除非每次插入都会使队列超出容量,否则将在每次插入时动态创建链接节点。
该队列对元素FIFO(先进先出)进行排序。队列的开头是已在队列中最长时间的元素。队列的尾部是最短时间位于队列中的元素。新元素插入到队列的尾部,并且队列检索操作在队列的开头获取元素。
Java中LinkedBlockingQueue的功能
- LinkedBlockingQueue是一个可选绑定的阻塞队列。
- Java LinkedBlockingQueue实现是线程安全的。该类中的所有排队方法都在内部使用ReentrantLock自动实现其效果。
- LinkedBlockingQueue不允许使用null元素。尝试添加,放置或者提供null时,它将引发NullPointerException。
public class LinkedBQ { public static void main(String[] args) { BlockingQueue bQueue = new LinkedBlockingQueue<>(); try { // putting null bQueue.put(null); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
输出:
Exception in thread "main" java.lang.NullPointerException at java.base/java.util.concurrent.LinkedBlockingQueue.put(LinkedBlockingQueue.java:325) at com.theitroad.programs.LinkedBQ.main(LinkedBQ.java:12)
Java LinkedBlockingQueue构造函数
- LinkedBlockingQueue()–创建一个容量为Integer.MAX_VALUE的LinkedBlockingQueue。
- LinkedBlockingQueue(int Capacity)–创建具有给定(固定)容量的LinkedBlockingQueue。
- LinkedBlockingQueue(Collection <?扩展E> c)–创建一个容量为Integer.MAX_VALUE的LinkedBlockingQueue,最初包含给定集合的元素,并以集合迭代器的遍历顺序添加。
LinkedBlockingQueue Java示例
BlockingQueue实现被设计为主要用于生产者-消费者队列,因此让我们来看一个使用LinkedBlockingQueue的生产者-消费者示例。
我们将创建一个容量为1的LinkedBlockingQueue,并分别使用put和take方法进行插入和检索操作。这些方法将无限期地阻塞当前线程,直到操作成功。由于队列容量为1,因此插入将被阻塞,直到队列中的元素被消耗为止。
public class LinkedBQ { public static void main(String[] args) { // shared queue BlockingQueue<Integer> bQueue = new LinkedBlockingQueue<>(1); ExecutorService executor = Executors.newFixedThreadPool(2); executor.execute(new LinkedProducer(bQueue)); executor.execute(new LinkedConsumer(bQueue)); executor.shutdown(); } } // Producer class LinkedProducer implements Runnable{ BlockingQueue<Integer> bQueue; LinkedProducer(BlockingQueue<Integer> bQueue){ this.bQueue = bQueue; } @Override public void run() { for(int i = 0; i < 5; i++){ try { bQueue.put(i); System.out.println("Added to queue-" + i); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } //Consumer class LinkedConsumer implements Runnable{ BlockingQueue<Integer> bQueue; LinkedConsumer(BlockingQueue<Integer> bQueue){ this.bQueue = bQueue; } @Override public void run() { for(int i = 0; i < 5; i++){ try { System.out.println("Consumer retrieved- " + bQueue.take()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
输出:
Added to queue-0 Consumer retrieved- 0 Added to queue-1 Consumer retrieved- 1 Added to queue-2 Consumer retrieved- 2 Added to queue-3 Consumer retrieved- 3 Consumer retrieved- 4 Added to queue-4
LinkedBlockingQueue类方法
在像LinkedBlockingQueue这样的BlockingQueue实现中,用于添加和删除元素的方法有四种形式
一个抛出异常,第二个返回一个特殊值(取决于操作,为null或者false),第三个无限期阻塞当前线程,直到操作成功为止,第四个仅放弃给定的最大时间限制。
插入方式
- add(E e)–如果可以立即将指定的元素插入此队列,而不会违反容量限制,则在成功时返回true,如果当前没有空间可用,则抛出IllegalStateException。
- offer(E e)–在不超出队列容量的情况下,可以立即在队列的尾部插入指定的元素,如果成功,则返回true;如果队列已满,则返回false。
- put(E e)–将指定的元素插入此队列的末尾,如有必要,等待空间变大。
- offer(E e,long timeout,TimeUnit unit)–将指定的元素插入此队列的尾部,如有必要,请等待指定的等待时间以使空间可用。
清除方法
- remove()–检索并删除此队列的头。如果此队列为空,则抛出NoSuchElementException。
- poll()–检索并删除此队列的头部,如果此队列为空,则返回null。
- take()–检索并删除此队列的头部,如有必要,请等待直到元素可用。
- poll(long timeout,TimeUnit unit)–检索并删除此队列的头,如果有必要使元素可用,则等待指定的等待时间。
其他重要方法清单
- clear()–以原子方式从此队列中删除所有元素。
- contains(Object o)–如果此队列包含指定的元素,则返回true。
- missingCapacity()–返回此队列理想情况下(在没有内存或者资源约束的情况下)可以无阻塞接受的其他元素的数量。
- remove(Object o)–从此队列中删除指定元素的单个实例(如果存在)。
- size()–返回此队列中的元素数。
- spliterator()–返回此队列中元素的分隔符。
- toArray()–按正确顺序返回包含此队列中所有元素的数组。