1 LinkedBlockingQueue核心属性
底层基于链表实现的,会将每个元素封装为Node,Node有当前值,还有一个next指针,默认情况下最大长度为Integer.MAX_VALUE,一般被称为无界队列。 LinkedBlockingQueue本质就是一个用Node封装的单向链表。
- Node
/**
* 阻塞队列元素会被封装为Node
*/
static class Node<E> {
E item;
Node<E> next;
Node(E x) { item = x; }
}
LinkedBlockingQueue内部提供了读锁和写锁,读写不互斥,而且记录数据条数的属性是AtomicInteger
/** 记录数据条数 */
private final AtomicInteger count = new AtomicInteger();
/** 读锁 */
private final ReentrantLock takeLock = new ReentrantLock();
private final Condition notEmpty = takeLock.newCondition();
/** 写锁 */
private final ReentrantLock putLock = new ReentrantLock();
private final Condition notFull = putLock.newCondition();
1.1 构造器
LinkedBlockingQueue可以通过构造器传入参数来限制队列的长度,如果不传,则默认为Integer.MAX_VALUE
另外还有一个传入集合类的构造器,capacity为Integer.MAX_VALUE,然后循环将集合内元素全部加入
/** 指定队列的长度,如果不传值,默认为Integer.MAX */
private final int capacity;
// 无参构造
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);
}
public LinkedBlockingQueue(Collection<? extends E> c) {
this(Integer.MAX_VALUE);
final ReentrantLock putLock = this.putLock;
// 可见行必要
putLock.lock();
try {
int n = 0;
for (E e : c) {
if (e == null)
throw new NullPointerException();
// 健壮性判断
if (n == capacity)
throw new IllegalStateException("Queue full");
enqueue(new Node<E>(e));
++n;
}
// 实际加入的个数
count.set(n);
} finally {
putLock.unlock();
}
}
2 LinkedBlockingQueue存取源码分析
2.1 存数据
- enqueue,实际插入链表的方法
// 插入数据到链表
private void enqueue(Node<E> node) {
last = last.next = node;
}
- offer,将非null数据插入链表,如果链表已满,则返回false
public boolean offer(E e) {
// 非空
if (e == null) throw new NullPointerException();
// 拿到count(记录当前数据条数)
final AtomicInteger count = this.count;
// 如果count达到了最大值
if (count.get() == capacity)
// 数据满了。
return false;
// 声明c
int c = -1;
// 将当前数据封装为Node
Node<E> node = new Node<E>(e);
// 添加写锁~
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
// !!DCL!!
// 再次拿到条数判断,如果还有空间,enqueue存数据
if (count.get() < capacity) {
// 数据放进来
enqueue(node);
// 拿到count,再自增
c = count.getAndIncrement();
// 添加完数据之后,长度依然小于最大长度,唤醒可能阻塞的写线程
// 读写不互斥,可能前面在执行时,队列是满的,但是读操作依然在进行
if (c + 1 < capacity)
notFull.signal();
}
} finally {
putLock.unlock();
}
// c == 0,说明添加数据之前,队列是空的,唤醒可能阻塞的读线程
if (c == 0)
signalNotEmpty();
// 返回count >= 0
return c >= 0;
}
- offer(E e, long timeout, TimeUnit unit), 将非null数据插入链表,如果链表已满则超时等待,超时后返回false
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
if (e == null) throw new NullPointerException();
long nanos = unit.toNanos(timeout);
int c = -1;
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
// 获取锁,可被中断
putLock.lockInterruptibly();
try {
// 超时等待
while (count.get() == capacity) {
if (nanos <= 0)
return false;
nanos = notFull.awaitNanos(nanos);
}
enqueue(new Node<E>(e));
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
return true;
}
- put,将非null数据插入链表,如果链表已满,阻塞等待
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;
// 获取锁,可被中断
putLock.lockInterruptibly();
try {
// 链表已满则阻塞等待
while (count.get() == capacity) {
notFull.await();
}
enqueue(node);
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
}
2.2 取数据
- dequeue,内部实际的取出方法,取出并改变链表头结点
private E dequeue() {
Node<E> h = head;
Node<E> first = h.next;
h.next = h; // help GC
head = first;
E x = first.item;
first.item = null;
return x;
}
- poll,取数据,队列为空则返回null
public E poll() {
final AtomicInteger count = this.count;
// 为0,没数据
if (count.get() == 0)
return null;
E x = null;
int c = -1;
// 读锁
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
// 如果队列有数据 DCL
if (count.get() > 0) {
x = dequeue();
// count --
c = count.getAndDecrement();
if (c > 1)
// c > 1,说明还有数据,唤醒读线程
notEmpty.signal();
}
} finally {
takeLock.unlock();
}
if (c == capacity)
// 到这说明还有位置呢,唤醒写线程
signalNotFull();
return x;
}
- poll(long timeout, TimeUnit unit),取数据,队列为空则超时等待,有数据则直接取出,超时后仍为空,返回null
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
final E x;
final int c;
long nanos = unit.toNanos(timeout);
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
// 超时等待
while (count.get() == 0) {
if (nanos <= 0L)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
// 取数据
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
- take,取数据,队列为空则阻塞至队列有数据后取出
public E take() throws InterruptedException {
final E x;
final int c;
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
while (count.get() == 0) {
notEmpty.await();
}
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}