LinkedBlockingDeque原始碼講解
阿新 • • 發佈:2018-12-12
尊重原創,轉載請標明出處 http://blog.csdn.net/abcdef314159
原始碼:\sources\Android-25
LinkedBlockingDeque是雙向連結串列阻塞佇列,他維護的是個連結串列節點Node,和前面的分析的PriorityBlockingQueue有一點區別,PriorityBlockingQueue維護的是個陣列。他和LinkedList很相似,不過LinkedList沒有指定容量,LinkedBlockingDeque是有容量大小的,大小為apacity,如果沒有指定apacity,那麼最大空間為Integer.MAX_VALUE.下面看一下LinkedBlockingDeque的主要方法。Node就是LinkedBlockingDeque維護的連結串列節點,這個節點有個前一個prev和後一個next,所以他維護的連結串列是雙向的。當然他還有兩個變數,一個是指向第一個,一個是指向最後一個/** Doubly-linked list node class */ static final class Node<E> { /** * The item, or null if this node has been removed. */ E item; /** * One of: * - the real predecessor Node * - this Node, meaning the predecessor is tail * - null, meaning there is no predecessor */ Node<E> prev; /** * One of: * - the real successor Node * - this Node, meaning the successor is head * - null, meaning there is no successor */ Node<E> next; Node(E x) { item = x; } }
LinkedBlockingDeque的構造方法比較多,下面隨便看其中的一個。/** * Pointer to first node. * Invariant: (first == null && last == null) || * (first.prev == null && first.item != null) */ transient Node<E> first; /** * Pointer to last node. * Invariant: (first == null && last == null) || * (last.next == null && last.item != null) */ transient Node<E> last;
下面來看一下linkFirst方法/** * Creates a {@code LinkedBlockingDeque} with a capacity of * {@link Integer#MAX_VALUE}, initially containing the elements of * the given collection, added in traversal order of the * collection's iterator. * * @param c the collection of elements to initially contain * @throws NullPointerException if the specified collection or any * of its elements are null */ public LinkedBlockingDeque(Collection<? extends E> c) { this(Integer.MAX_VALUE); final ReentrantLock lock = this.lock; lock.lock(); // Never contended, but necessary for visibility try { for (E e : c) { if (e == null) throw new NullPointerException(); if (!linkLast(new Node<E>(e)))//不停的新增到隊尾,如果空間滿就會丟擲異常 throw new IllegalStateException("Deque full"); } } finally { lock.unlock(); } }
/**
* Links node as first element, or returns false if full.
*/
private boolean linkFirst(Node<E> node) {
//新增到第一個節點的前面
// assert lock.isHeldByCurrentThread();
//如果已經滿了,就直接返回false。
if (count >= capacity)
return false;
Node<E> f = first;
//讓原來的頭結點成為新節點的下一個節點。
node.next = f;
//讓新節點成為first節點
first = node;
//如果last為null,說明原來連結串列是為null的,也讓尾節點指向新節點
if (last == null)
last = node;
else
//node已經是連結串列的頭結點了,讓node等於f的前一個節點,因為連結串列是雙向的。
//為什麼last等於null的時候不執行這段程式碼,是因為last等於null的時候表示
//沒有節點的,新增的時候就一個節點。
f.prev = node;
++count;//連結串列數量加1
notEmpty.signal();
return true;
}
接著再看下一個方法linkLast
/**
* Links node as last element, or returns false if full.
*/
private boolean linkLast(Node<E> node) {
// assert lock.isHeldByCurrentThread();
// 新增到連結串列的尾,如果滿了,直接返回false
if (count >= capacity)
return false;
Node<E> l = last;
//既然是新增到尾節點,那麼之前尾節點就是新節點的前一個節點。
node.prev = l;
//然後讓last指向新節點
last = node;
if (first == null)
//如果原來節點為空,同時也讓新節點成為首節點。
first = node;
else
//因為是雙向連結串列,所以這裡讓新節點成為原來尾節點的下一個節點
l.next = node;
++count;//連結串列數量加1
notEmpty.signal();
return true;
}
再看下一個方法unlinkFirst,斷開首節點
/**
* Removes and returns first element, or null if empty.
*/
private E unlinkFirst() {
//移除第一個節點。
// assert lock.isHeldByCurrentThread();
Node<E> f = first;
if (f == null)
return null;
//儲存首節點的下一個節點
Node<E> n = f.next;
E item = f.item;
f.item = null;
//讓首節點成為首節點的下一個節點的,就是自己的下一個指向自己,因為是first節點,
//首節點的前一個為空,所以這裡其實就是讓首節點與連結串列斷開了
f.next = f; // help GC
//讓first節點指向first的下一個節點。
first = n;
if (n == null)
last = null;
else
//既然n是首節點了,那麼他的前一個肯定要為null的
n.prev = null;
--count;//數量減1
notFull.signal();
return item;
}
接著是unlinkLast方法,表示斷開最後一個節點
/**
* Removes and returns last element, or null if empty.
*/
private E unlinkLast() {
// assert lock.isHeldByCurrentThread();
Node<E> l = last;
//如果為空,直接返回
if (l == null)
return null;
//儲存最後一個節點的前一個節點
Node<E> p = l.prev;
E item = l.item;
l.item = null;
//讓最後一個節點的前一個指向自己,相當於最後一個節點與
//連結串列斷開。
l.prev = l; // help GC
//然後讓last指向之前最後一個連結串列的前一個
last = p;
//如果等於null,相當於連結串列直接刪除。
if (p == null)
first = null;
else
//否則讓最後一個連結串列的下一個指向null
p.next = null;
--count;//數量減1
notFull.signal();
return item;
}
繼續看,下面一個是unlink方法
/**
* Unlinks x.
*/
void unlink(Node<E> x) {
// assert lock.isHeldByCurrentThread();
//儲存當前節點的前一個和後一個
Node<E> p = x.prev;
Node<E> n = x.next;
if (p == null) {
//如果前一個等於null,說明x是first節點,直接刪除first節點即可
unlinkFirst();
} else if (n == null) {
//如果後一個等於null,說明x是尾節點,直接刪除last節點即可
unlinkLast();
} else {
//連結串列的斷開其實很簡單,就是讓當前節點的下一個成為當前節點前一個的下一個,
//當前節點的前一個成為當前節點下一個的前一個。
p.next = n;
n.prev = p;
x.item = null;
// Don't mess with x's links. They may still be in use by
// an iterator.
--count;
notFull.signal();
}
}
接著看offerFirst方法,其實程式碼很簡單
/**
* @throws NullPointerException {@inheritDoc}
*/
public boolean offerFirst(E e) {
if (e == null) throw new NullPointerException();
Node<E> node = new Node<E>(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
return linkFirst(node);//斷開首節點
} finally {
lock.unlock();
}
}
然後add,offe,put,remove,pollFirst,pollLast,takeFirst,takeLast,pollFirst,pollLast基本上都呼叫上面的方法,都很簡單,這裡就不在介紹。