本文已收录至 https://github.com/vipstone/algorithm 《算法图解》系列。
通过前面文章的学习《一文详解「队列」,手撸队列的3种方法!》我们知道了队列(Queue)是先进先出(FIFO)的,并且我们可以用数组、链表还有 List 的方式来实现自定义队列,那么本文我们来系统的学习一下官方是如何实现队列的。
Java 中的队列有很多,例如:ArrayBlockingQueue
、LinkedBlockingQueue
、PriorityQueue
、DelayQueue
、SynchronousQueue
等,那它们的作用是什么?又是如何分类的呢?
其实 Java 中的这些队列可以从不同的维度进行分类,例如可以从阻塞和非阻塞进行分类,也可以从有界和无界进行分类,而本文将从队列的功能上进行分类,例如:优先队列、普通队列、双端队列、延迟队列等。
虽然本文的重点是从功能上对队列进行解读,但其它分类也是 Java 中的重要概念,所以我们先来了解一下它们。
阻塞队列和非阻塞队列
阻塞队列(Blocking Queue)提供了可阻塞的 put
和 take
方法,它们与可定时的 offer
和 poll
是等价的。如果队列满了 put
方法会被阻塞等到有空间可用再将元素插入;如果队列是空的,那么 take
方法也会阻塞,直到有元素可用。当队列永远不会被充满时,put
方法和 take
方法就永远不会阻塞。
我们可以从队列的名称中知道此队列是否为阻塞队列,阻塞队列中包含 BlockingQueue
关键字,比如以下这些:
- ArrayBlockingQueue
- LinkedBlockingQueue
- PriorityBlockingQueue
- .......
阻塞队列功能演示
接下来我们来演示一下当阻塞队列的容量满了之后会怎样,示例代码如下:
import java.util.Date; import java.util.concurrent.ArrayBlockingQueue; public class BlockingTest { public static void main(String[] args) throws InterruptedException { // 创建一个长度为 5 的阻塞队列 ArrayBlockingQueue q1 = new ArrayBlockingQueue(5); // 新创建一个线程执行入列 new Thread(() -> { // 循环 10 次 for (int i = 0; i < 10; i++) { try { q1.put(i); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(new Date() + " | ArrayBlockingQueue Size:" + q1.size()); } System.out.println(new Date() + " | For End."); }).start(); // 新创建一个线程执行出列 new Thread(() -> { for (int i = 0; i < 5; i++) { try { // 休眠 1S Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if (!q1.isEmpty()) { try { q1.take(); // 出列 } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } }
以上代码的执行结果如下:
Mon Oct 19 20:16:12 CST 2020 | ArrayBlockingQueue Size:1
Mon Oct 19 20:16:12 CST 2020 | ArrayBlockingQueue Size:2
Mon Oct 19 20:16:12 CST 2020 | ArrayBlockingQueue Size:3
Mon Oct 19 20:16:12 CST 2020 | ArrayBlockingQueue Size:4
Mon Oct 19 20:16:12 CST 2020 | ArrayBlockingQueue Size:5
Mon Oct 19 20:16:13 CST 2020 | ArrayBlockingQueue Size:5
Mon Oct 19 20:16:14 CST 2020 | ArrayBlockingQueue Size:5
Mon Oct 19 20:16:15 CST 2020 | ArrayBlockingQueue Size:5
Mon Oct 19 20:16:16 CST 2020 | ArrayBlockingQueue Size:5
Mon Oct 19 20:16:17 CST 2020 | ArrayBlockingQueue Size:5
Mon Oct 19 20:16:17 CST 2020 | For End.
从上述结果可以看出,当 ArrayBlockingQueue
队列满了之后就会进入阻塞,当过了 1 秒有元素从队列中移除之后,才会将新的元素入列。