public class LinkedBlockingQueue<E>
extends AbstractQueue<E>
implements BlockingQueue<E>, Serializable
/**
*基于链表节点的可选有界阻塞队列。此队列对元素FIFO(先进先出)进行排序。
*队列的头是队列中出现时间最长的元素。队列的尾部是在队列中出现的时间最短的元素。
*在队列的尾部插入新元素,队列检索操作在队列的头部获取元素。
*与基于阵列的队列相比,链接队列通常具有更高的吞吐量,但在大多数并发应用程序中,其性能不太可预测。
*
*如果未指定,则容量等于Integer.MAX_值。每次插入时都会动态创建链接节点,除非这会使队列超过容量。
*因此建议指定容量以免内存泄漏
*
*这个类及其迭代器实现了集合和迭代器接口的所有可选方法。
*这个类是Java集合框架的成员。
* @since 1.5
* @author Doug Lea
**/
public class LinkedBlockingQueue<E>
extends AbstractQueue<E>
implements BlockingQueue<E>, Serializable
属性分析
/**
* 链表节点类
*/
static class Node<E> {
E item;
/**
* One of:
* - 下一个后继节点,是
* - 如果为null表示此节点为最后一个节点
*/
Node<E> next;
Node(E x) { item = x; }
}
/** 队列边界,如果不指定大小为Integer.MAX_VALUE */
private final int capacity;
/** 队列元素数量 */
private final AtomicInteger count = new AtomicInteger();
/**
* 队列头节点
* Invariant: head.item == null
*/
transient Node<E> head;
/**
* 队列尾节点
* Invariant: last.next == null
*/
private transient Node<E> last;
/**出列锁 */
private final ReentrantLock takeLock = new ReentrantLock();
/** 出列信号 */
private final Condition notEmpty = takeLock.newCondition();
/** 入列锁 */
private final ReentrantLock putLock = new ReentrantLock();
/** 入列信号 */
private final Condition notFull = putLock.newCondition();
每个添加到LinkedBlockingQueue队列中的数据都将被封装成Node节点,添加的链表队列中,其中head和last分别指向队列的头结点和尾结点。与ArrayBlockingQueue不同的是,LinkedBlockingQueue内部分别使用了takeLock 和 putLock 对并发进行控制,也就是说,添加和删除操作并不是互斥操作,可以同时进行,这样也就可以大大提高吞吐量。
这里如果不指定队列的容量大小,也就是使用默认的Integer.MAX_VALUE,如果存在添加速度大于删除速度时候,有可能会内存溢出
另外,LinkedBlockingQueue对每一个lock锁都提供了一个Condition用来挂起和唤醒其他线程。
由于ArrayBlockingQueue采用的是数组的存储容器,因此在插入或删除元素时不会产生或销毁任何额外的对象实例,而LinkedBlockingQueue则会生成一个额外的Node对象。这可能在长时间内需要高效并发地处理大批量数据的时,对于GC可能存在较大影响。
构造方法:
/**
*
* 创造一个容量为Integer.MAX_VALUE的的对象
*/
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
/**
* 创造一个给定大小的队列.
*
* @param 队列大小
* @throws IllegalArgumentException 如果参数不大于0
*
*/
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node<E>(null);
}
/**
*
* 创造一个包含指定集和的队列,队列容量为Integer.MAX_VALUE,集合按照遍历顺序添加进队列
*
* @param c 指定集合
* @throws NullPointerException 如果集合未申明或者集合元素为空
*
*/
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;
}
//元素个数设置为n
count.set(n);
} finally {
//释放入列锁
putLock.unlock();
}
}
重要方法分析:
/**
* 唤醒出列线程,同时锁住出列线程,达到线程并发安全
*/
private void signalNotEmpty() {
final ReentrantLock takeLock = this.takeLock;
//获得出列锁,达到线程并发安全
takeLock.lock();
try {
//唤醒出列线程
notEmpty.signal();
} finally {
//释放出列锁
takeLock.unlock();
}
}
/**
* 唤醒入列线程,同时锁住入列线程
*/
private void signalNotFull() {
final ReentrantLock putLock = this.putLock;
//获得出列锁,达到线程并发安全
putLock.lock();
try {
//唤醒入列线程
notFull.signal();
} finally {
//释放入列锁
putLock.unlock();
}
}
//*********************************************入列方法*****************************************************
/**
* 将节点插入队尾.
*
* @param node the node
*/
private void enqueue(Node<E> node) {
// assert putLock.isHeldByCurrentThread();
// assert last.next == null;
last = last.next = node;
}
/**
* 移除头节点.
*
* 返回头节点
*/
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;
}
/**
* 将元素添加至对尾巴, 如果队列慢了就阻塞等待可用空间
*
* @throws InterruptedException 线程打断异常
* @throws NullPointerException 空指针异常
*/
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;
//取得入列锁,如果期间被其他线程打断报InterruptedException异常
putLock.lockInterruptibly();
try {
/*
* 当元素数量等于队列容量,阻塞入列线
*/
while (count.get() == capacity) {
//阻塞,直到notFull.signal();
notFull.await();
}
//插入到队列
enqueue(node);
c = count.getAndIncrement();
//如果队列元素个数小于容量,唤醒入列队列
if (c + 1 < capacity)
notFull.signal();
} finally {
//释放入列锁
putLock.unlock();
}
if (c == 0)
//只要有一个元素在队列,就唤醒出列线程
signalNotEmpty();
}
/**
*
* 将元素添加至对尾巴, 如果队列慢了就阻塞等待指定时间直到有可用空间
*
* @return {@code true} 如果添加成功返回true
* @throws InterruptedException 线程打断异常
* @throws NullPointerException 空指针异常
*/
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;
//取得入列锁,如果期间被其他线程打断报InterruptedException异常
putLock.lockInterruptibly();
try {
while (count.get() == capacity) {
//指定时间不大于0直接返回false
if (nanos <= 0L)
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;
}
/**
*
* 在队尾插入
* 成功返回true,失败返回false
*当使用容量受限队列时,此方法通常比方法add更可取,后者只能通过抛出异常才能插入元素。
*
* @throws NullPointerException 元素为空
*/
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
final AtomicInteger count = this.count;
if (count.get() == capacity)
return false;
int c = -1;
Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
if (count.get() < capacity) {
enqueue(node);
c = count.getAndIncrement();
if (c + 1 < capacity)
//元素个数小于容量,唤醒入列线程
notFull.signal();
}
} finally {
//释放入列锁
putLock.unlock();
}
if (c == 0)
//只要有一个元素在队列,就唤醒出列线程
signalNotEmpty();
return c >= 0;
}
//*********************************************出列方法*****************************************************
/**
* 从对头移除元素
*
* @return 返回头节点
*/
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;
}
/**
* 从对头移除元素
*
* @return 返回头节点
*如果被其他线程打断报InterruptedException
*/
public E take() throws InterruptedException {
E x;
int c = -1;
//元素个数
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
//获取出列锁,如果被其他线程打断报InterruptedException
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;
}
/**
*
*从对头删除元素并返回,如果队列为空等待指定时间再循环判断队列元素个数
*如果时间参数错误,直接返回null
*
* @throws InterruptedException 间被其他线程打断报InterruptedException异常
*/
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
E x = null;
int c = -1;
long nanos = unit.toNanos(timeout);
//元素数量
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
//获取出列锁,期间被其他线程打断报InterruptedException异常
takeLock.lockInterruptibly();
try {
while (count.get() == 0) {
if (nanos <= 0L)
// 时间参数错误,直接返回null
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;
}
/**
*
*从对头删除元素并返回,如果队列为空直接返回null
*
*/
public E poll() {
//元素数量
final AtomicInteger count = this.count;
if (count.get() == 0)
//队列为空返回null
return null;
E x = null;
int c = -1;
final ReentrantLock takeLock = this.takeLock;
//获得出列锁
takeLock.lock();
try {
if (count.get() > 0) {
//删除并返回头节点
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
//唤醒出列线程
notEmpty.signal();
}
} finally {
//释放出列锁
takeLock.unlock();
}
if (c == capacity)
//只要元素数量小于容量,就唤醒入列线程
signalNotFull();
return x;
}
public E peek() {
if (count.get() == 0)
return null;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
return (count.get() > 0) ? head.next.item : null;
} finally {
takeLock.unlock();
}
}
方法过多不一一说明如果需要查看请查阅官方文档https://docs.oracle.com/javase/8/docs/api/或者看源码