Java并发编程—阻塞队列
并发队列
Java 提供的线程安全的队列(也称为并发队列)分为阻塞队列和非阻塞队列两大类。
阻塞队列的典型例子就是 BlockingQueue 接口的实现类,BlockingQueue 下面有 6 种最主要的实现,分别是 ArrayBlockingQueue(有界)、LinkedBlockingQueue(无界)、SynchronousQueue、DelayQueue、PriorityBlockingQueue 和 LinkedTransferQueue
非阻塞并发队列的典型例子是 ConcurrentLinkedQueue,这个类不会让线程阻塞,利用 CAS 保证了线程安全。
Deque 接口,它继承了 Queue。Deque 的意思是双端队列,音标是 [dek],是 double-ended-queue 的缩写,它从头和尾都能添加和删除元素
方法纵览
1)抛出异常
1.1 add方法
当队列已满时再添加元素会报出异常
Exception in thread "main" java.lang.IllegalStateException:Queue full
1.2 remove方法
当队列已空时再删除元素会报出异常
Exception in thread "main" java.util.NoSuchElementException
1.3 element
返回队列的头部节点,和remove相同,但不删除。如果队列为空会报出和remove一样的异常
2)返回结果但不抛出异常
2.1 offer方法
插入一个元素,并用返回值来表示是否插入成功,不会报异常。
2.2 poll方法
删除头部节点,如果队列为空,会返回null。所以队列中不允许插入null值
2.3 peek方法
和poll相同,但不删除元素。
offer和poll都带有超时的重载方法
3)阻塞
3.1 put方法
插入元素,如果队列已满,则让插入的线程陷入阻塞
3.2 take方法
移除头部元素,如果队列为空,则让删除的线程陷入阻塞
常见的阻塞队列
ArrayBlockingQueue
ArrayBlockingQueue 是最典型的有界队列,其内部是用数组存储元素的,利用 ReentrantLock 实现线程安全。我们在创建它的时候就需要指定它的容量,之后也不可以再扩容了,在构造函数中我们同样可以指定是否是公平的
LinkedBlockingQueue
内部用链表实现的 BlockingQueue。如果我们不指定它的初始容量,那么它容量默认就为整型的最大值 Integer.MAX_VALUE,所以 LinkedBlockingQueue 也被称作无界队列
SynchronousQueue
它的容量为 0,所以没有一个地方来暂存元素,导致每次取数据都要先阻塞,直到有数据被放入;同理,每次放数据的时候也会阻塞,直到有消费者来取。
PriorityBlockingQueue
PriorityBlockingQueue 是一个支持优先级的无界阻塞队列,可以通过自定义类实现