关于Java中阻塞队列BlockingQueue的详解
作者:书启秋枫
栈与队列概念
栈(Stack):先进后出,后进先出
队列:先进先出
1. 什么是BlockingQueue
在多线程领域:所谓阻塞,在某些情况下会挂起线程(即阻塞),一旦条件满足,被挂起的线程又会自动被唤起。
BlockingQueue即阻塞队列,是java.util.concurrent下的一个接口,因此不难理解,BlockingQueue是为了解决多线程中数据高效安全传输而提出的。从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞。被阻塞的情况主要有如下两种:
- 当队列满了的时候进行入队列操作
- 当队列空了的时候进行出队列操作
因此,当一个线程试图对一个已经满了的队列进行入队列操作时,它将会被阻塞,除非有另一个线程做了出队列操作;同样,当一个线程试图对一个空队列进行出队列操作时,它将会被阻塞,除非有另一个线程进行了入队列操作。
阻塞队列主要用在生产者/消费者的场景,下面这幅图展示了一个线程生产、一个线程消费的场景:
为什么需要BlockingQueue?
好处是我们不需要关心什么时候需要阻塞线程,什么时候需要唤醒线程,因为这一切BlockingQueue都给你一手包办了。在concurrent包发布以前,在多线程环境下,我们每个程序员都必须去自己控制这些细节,尤其还要兼顾效率和线程安全,而这会给我们的程序带来不小的复杂度。
2. 认识BlockingQueue
java.util.concurrent 包里的 BlockingQueue是一个接口,继承Queue接口,Queue接口继承 Collection。
BlockingQueue接口主要有以下7个实现类:
- ArrayBlockingQueue:由数组结构组成的有界阻塞队列。
- LinkedBlockingQueue:由链表结构组成的有界(但大小默认值为integer.MAX_VALUE)阻塞队列。
- PriorityBlockingQueue:支持优先级排序的无界阻塞队列。
- DelayQueue:使用优先级队列实现的延迟无界阻塞队列。
- SynchronousQueue:不存储元素的阻塞队列,也即单个元素的队列。
- LinkedTransferQueue:由链表组成的无界阻塞队列。
- LinkedBlockingDeque:由链表组成的双向阻塞队列。
BlockingQueue接口有以下几个方法:它的方法可以分成以下4类:
抛出异常 | 特殊值 | 阻塞 | 超时 | |
插入 | add(e) | offer(e) | put(e) | offer(e, time, unit) |
移除 | remove() | poll() | take() | poll(time, unit) |
检查 | element() | peek() | 不可用 | 不可用 |
① 抛出异常
add正常执行返回true,element(不删除)和remove返回阻塞队列中的第一个元素 当阻塞队列满时,再往队列里add插入元素会抛IllegalStateException:Queue full 当阻塞队列空时,再往队列里remove移除元素会抛NoSuchElementException 当阻塞队列空时,再调用element检查元素会抛出NoSuchElementException。
② 特定值
插入方法,成功ture失败false 移除方法,成功返回出队列的元素,队列里没有就返回null 检查方法,成功返回队列中的元素,没有返回null。
③ 一直阻塞
如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行。 当阻塞队列满时,再往队列里put元素,队列会一直阻塞生产者线程直到put数据or响应中断退出 当阻塞队列空时,再从队列里take元素,队列会一直阻塞消费者线程直到队列可用。
④ 超时退出
如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行,但等待时间不会超过给定值。 返回一个特定值以告知该操作是否成功(典型的是 true / false)。
3. 代码演示
public class BlockingQueueDemo { public static void main(String[] args) throws InterruptedException { BlockingQueue<String> queue = new ArrayBlockingQueue<>(3); // 第一组方法:add remove element // System.out.println(queue.add("a")); // System.out.println(queue.add("b")); // System.out.println(queue.add("c")); // // System.out.println(queue.add("d")); // // System.out.println(queue.element()); // System.out.println(queue.remove()); // System.out.println(queue.remove()); // System.out.println(queue.remove()); // //System.out.println(queue.remove()); // //System.out.println(queue.element()); // 第二组:offer poll peek // System.out.println(queue.offer("a")); // System.out.println(queue.offer("b")); // System.out.println(queue.offer("c")); // System.out.println(queue.offer("d")); // System.out.println(queue.peek()); // System.out.println(queue.poll()); // System.out.println(queue.poll()); // System.out.println(queue.poll()); // System.out.println(queue.poll()); // System.out.println(queue.peek()); // 第三组:put take // queue.put("a"); // queue.put("b"); // queue.put("c"); // System.out.println(queue.take()); // queue.put("d"); // System.out.println(queue.take()); // System.out.println(queue.take()); // System.out.println(queue.take()); // 第四组:offer poll System.out.println(queue.offer("a")); System.out.println(queue.offer("b")); System.out.println(queue.offer("c")); System.out.println(queue.offer("d", 5, TimeUnit.SECONDS)); } }
到此这篇关于关于Java中阻塞队列BlockingQueue的详解的文章就介绍到这了,更多相关Java阻塞队列BlockingQueue内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!