簡介
LinkedBlockingQueue 字義爲鏈式阻塞隊列,既然是鏈式,那麼內部肯定以鏈接結構存儲了,相比ArrayBlockingQueue,可以是一個無界隊列,但是性能比之要差。
初始化
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(); // 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>(e));
++n;
}
//計數器
count.set(n);
} finally {
putLock.unlock();
}
}
private void enqueue(Node<E> node) {
// assert putLock.isHeldByCurrentThread();
// assert last.next == null;
//設置尾節點
last = last.next = node;
}
入隊
//入隊操作使用putLock 出隊使用lock 即兩個是入隊和出隊使用的是不一樣的鎖
//可線程打斷拋異常
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);
//計數器加1
c = count.getAndIncrement();
//達到臨界值 不滿條件通知,因爲另一個線程有可能再出隊
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
}
//可過期入隊 過期返回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 {
//循環判斷 如果隊列已滿並且過期返回false
while (count.get() == capacity) {
if (nanos <= 0)
return false;
//阻塞
nanos = notFull.awaitNanos(nanos);
}
//入隊
enqueue(new Node<E>(e));
//計數器+1
c = count.getAndIncrement();
//不滿條件通知
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
return true;
}
//入隊,如果隊列已滿 則 返回false
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;
}
出隊
//直到獲取元素爲止,打斷拋異常
public E take() throws InterruptedException {
E x;
int c = -1;
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;
}
//出隊
private E dequeue() {
//讓原先的head被gc回收 head設置爲原先的next並且item設置爲null
Node<E> h = head;
Node<E> first = h.next;
h.next = h;
head = first;
E x = first.item;
first.item = null;
return x;
}
//可一段時間內獲取
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();
//計數器-1
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)
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 {
//獲取當前元素返回
Node<E> first = head.next;
if (first == null)
return null;
else
return first.item;
} finally {
takeLock.unlock();
}
}
//移除
public boolean remove(Object o) {
if (o == null) return false;
//出隊、入隊全鎖
fullyLock();
try {
//從頭部開始循環查找匹配元素
for (Node<E> trail = head, p = trail.next;
p != null;
trail = p, p = p.next) {
if (o.equals(p.item)) {
unlink(p, trail);
return true;
}
}
return false;
} finally {
//釋放出隊入隊鎖
fullyUnlock();
}
}
void unlink(Node<E> p, Node<E> trail) {
//去除p節點 用p.next 代替
p.item = null;
trail.next = p.next;
if (last == p)
last = trail;
//計數器-1 不滿條件通知 這裏有個疑問是:不需要判斷 因爲remove中使用了fullyLock 所以 移除一個 肯定是不滿的
if (count.getAndDecrement() == capacity)
notFull.signal();
}
總結
如果是不確定數組大小的,則可以使用LinkedBlockingQueue(也可以指定),確定使用ArrayBlockingQueue