一、概述
LinkedBlockingQueue是一个单向链表的阻塞队列,FIFO队列,是无界队列,当前如果初始化的时候指定大小,也可以是有界队列。
二、思想
LinkedBlockingQueue思想:
- 数据结构是单向链表,同时维护一个头节点head和尾节点last
- 生产者和消费者使用同一个队列
- 生产者和消费者分别使用自己的锁,读写分离,生产者使用putLock,消费者使用takeLock
- 生产者只有在队列未满时生产,队列满时生产者线程就进行阻塞
- 消费者只有在队列有数据时消费,队列没有数据消费者线程就进行阻塞
三、源码解析
构造函数
默认是无界队列
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
如果需要指定队列大小,使用如下构造函数
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node<E>(null);
}
生产入队
put(E e)
队列添加数据,如果队列已满阻塞等待
public void put(E e) throws InterruptedException {
// 不允许添加空数据
if (e == null) throw new NullPointerException();
// 队列变动前的数量
int c = -1;
Node<E> node = new Node<E>(e);
// 写锁
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
// lockInterruptibly这个是可以响应线程中断的锁
putLock.lockInterruptibly();
try {
// 如果队列当前数量和容量相等,说明已经满了,就阻塞等待
while (count.get() == capacity) {
notFull.await();
}
// 在队列链表尾部添加元素FIFO
enqueue(node);
// 队列当前数量+1,并将变动前的队列数量赋值给c
c = count.getAndIncrement();
// 如果队列还没有满,就唤醒通知入队阻塞的线程可以生产
if (c + 1 < capacity)