一:功能介绍
基于单项链表,FIFO的有界阻塞队列,内部采用可重入锁ReentrantLock实现,一个take锁,一个put锁,相应的等待条件也为二个。
二:源码分析
package java.util.concurrent;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.AbstractQueue;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class LinkedBlockingQueue extends AbstractQueue
implements BlockingQueue, java.io.Serializable {
private static final long serialVersionUID = -6903933977591709194L;
//静态内部类Node
static class Node {
//节点元素
E item;
//指向某个节点的下一个节点的引用
Node next;
Node(E x) { item = x; }
}
//链表的容量
private final int capacity;
//原子类型,统计队列里面链表节点的个数
private final AtomicInteger count = new AtomicInteger(0);
//链表的头节点
private transient Node head;
//链表的尾节点
private transient Node 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();
//队列有数据,唤醒所有等待获取队列数据的线程
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();
}
}
//插入节点到尾部
private void enqueue(Node node) {
//1:设置未插入节点前尾部节点的下一个节点引用为当前需要插入的节点
//2:将当前需要插入的节点定义为尾部节点
last = last.next = node;
}
//移除数据
private E dequeue() {
Node h = head;
Node first = h.next;
h.next = h; // help GC
//将头节点的下一个节点设为新的头部节点
head = first;
//返回节点数据
E x = first.item;
first.item = null;
return x;
}
//获取插入锁,获取锁
void fullyLock() {
putLock.lock();
takeLock.lock();
}
//释放插入锁,获取锁
void fullyUnlock() {
takeLock.unlock();
putLock.unlock();
}
//若不指定初始化容量,默认为int的最大值
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
//构造函数
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
//初始化时,头部节点,尾部节点都为null
last = head = new Node(null);
}
//初始化时刻指定存储默认的数据
public LinkedBlockingQueue(Collection extends E> c) {
this(Integer.MAX_VALUE);
final ReentrantLock putLock = this.putLock;
putLock.lock(); // Never contended, but necessary for visibility
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));
++n;
}
//原子设置节点大小
count.set(n);
} finally {
putLock.unlock();
}
}
//返回链表节点的数量
public int size() {
return count.get();
}
//返回还可以有多少的容量可供插入
public int remainingCapacity() {
return capacity - count.get();
}
//入队操作
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
int c = -1;
//new一个Node
Node node = new Node(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
//插入数据的可中断锁,只要interrupted,立马中断
putLock.lockInterruptibly();
try {
//如果队列满了
while (count.get() == capacity) {
notFull.await();
}
//入队
enqueue(node);
c = count.getAndIncrement();
//如果插入数据后队列容量未满
if (c + 1 < capacity)
//唤醒等待插入的线程
notFull.signal();
} finally {
putLock.unlock();
}
//如果未插入节点前,队列为空,那么在插入节点后,就需要唤醒等待take的线程
if (c == 0)
signalNotEmpty();
}
//也是入队操作,成功返回true,多了个超时,其他同put,这里就不解释了
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));
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
return true;
}
//入队操作,入队OK返回true
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
final AtomicInteger count = this.count;
//如果队列容量满了,直接返回false
if (count.get() == capacity)
return false;
int c = -1;
Node node = new Node(e);
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
//如果队列容量未满
if (count.get() < capacity) {
//入队,插入到队尾
enqueue(node);
//数量+1
c = count.getAndIncrement();
//如果入队尾后,容量还有,唤醒后面阻塞的等待入队的线程
if (c + 1 < capacity)
notFull.signal();
}
} finally {
putLock.unlock();
}
//如果未插入节点前,队列为空,那么在插入节点后,就需要唤醒等待take的线程
if (c == 0)
signalNotEmpty();
return c >= 0;
}
//出队操作,获取头部节点
public E take() throws InterruptedException {
E x;
int c = -1;
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
//如果没有节点,take线程阻塞
while (count.get() == 0) {
notEmpty.await();
}
//获取头部节点,出队
x = dequeue();
c = count.getAndDecrement();
//如果还有节点,唤醒后面等待take的线程
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();
}
//如果未take之前,队列是满的,那么在take一次之后,队列未满,唤醒阻塞的put操作的线程
if (c == capacity)
signalNotFull();
return x;
}
//同poll(),只是多了超时限制
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;
takeLock.lockInterruptibly();
try {
while (count.get() == 0) {
if (nanos <= 0)
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;
}
//获取并移除队列的头部节点
public E poll() {
final AtomicInteger count = this.count;
//没有数据,直接返回null
if (count.get() == 0)
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();
//唤醒阻塞的take线程
if (c > 1)
notEmpty.signal();
}
} finally {
takeLock.unlock();
}
//如果未移除前,队列是满的,移除后,队列未满,唤醒阻塞的put线程
if (c == capacity)
signalNotFull();
return x;
}
//获取头部数据,但不移除队列头
public E peek() {
//队列没有数据,return null
if (count.get() == 0)
return null;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
Node first = head.next;
if (first == null)
return null;
else
return first.item;
} finally {
takeLock.unlock();
}
}
//是否包含,遍历链表equals判断,如果链表较长,请求太靠后,比较耗性能
public boolean contains(Object o) {
if (o == null) return false;
fullyLock();
try {
for (Node p = head.next; p != null; p = p.next)
if (o.equals(p.item))
return true;
return false;
} finally {
fullyUnlock();
}
}
//返回数组
public Object[] toArray() {
fullyLock();
try {
int size = count.get();
Object[] a = new Object[size];
int k = 0;
for (Node p = head.next; p != null; p = p.next)
//数组的每一项存在队列链表节点的内容
a[k++] = p.item;
return a;
} finally {
fullyUnlock();
}
}
//遍历
public Iterator iterator() {
return new Itr();
}
private class Itr implements Iterator {
//当前节点
private Node current;
//上一个返回的节点
private Node lastRet;
//当前节点对应的节点数据
private E currentElement;
Itr() {
fullyLock();
try {
current = head.next;
if (current != null)
currentElement = current.item;
} finally {
fullyUnlock();
}
}
//只要当前节点的下一个节点引用还存在
public boolean hasNext() {
return current != null;
}
/**
* Returns the next live successor of p, or null if no such.
*
* Unlike other traversal methods, iterators need to handle both:
* - dequeued nodes (p.next == p)
* - (possibly multiple) interior removed nodes (p.item == null)
*/
private Node nextNode(Node p) {
for (;;) {
Node s = p.next;
if (s == p)
return head.next;
if (s == null || s.item != null)
return s;
p = s;
}
}
//获取下一个节点
public E next() {
fullyLock();
try {
if (current == null)
throw new NoSuchElementException();
E x = currentElement;
//将当前节点当做上一次返回的节点
lastRet = current;
//获取当前节点的下一个节点
current = nextNode(current);
currentElement = (current == null) ? null : current.item;
return x;
} finally {
fullyUnlock();
}
}
public void remove() {
if (lastRet == null)
throw new IllegalStateException();
fullyLock();
try {
Node node = lastRet;
lastRet = null;
for (Node trail = head, p = trail.next;
p != null;
trail = p, p = p.next) {
if (p == node) {
unlink(p, trail);
break;
}
}
} finally {
fullyUnlock();
}
}
}
}