LinkedBlockingQueue原始碼解讀
Node LinkedBlockingQueue連結串列節點,單向節點
//Node節點類,單向節點
static class Node<E> {
E item;
/**
* One of:
* - the real successor Node
繼任節點
* - this Node, meaning the successor is head.next
* - null, meaning there is no successor (this is the last node)
next為空意味當前節點為鏈尾
*/
Node<E> next;
Node(E x) { item = x; }
}
構造方法
//預設無界佇列
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
LinkedBlockingQueue指定容量,鏈頭和鏈尾都非空物件但item為空
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node<E>(null);
}
全域性變數
/** The capacity bound, or Integer.MAX_VALUE if none */
//連結串列容量,預設Integer.MAX_VALUE,即無界佇列
private final int capacity;
/** Current number of elements */
//當前佇列元素總量
private final AtomicInteger count = new AtomicInteger();
/**
* Head of linked list. 鏈頭
* Invariant: head.item == null //不變形:鏈頭元素永為空
*/
transient Node<E> head;
/**
* Tail of linked list. 鏈尾
* Invariant: last.next == null //不變形:鏈尾元素後再無元素
*/
private transient Node<E> last;
/** Lock held by take, poll, etc */
//拿鎖,在 take, poll等方法時會請求
private final ReentrantLock takeLock = new ReentrantLock();
/** Wait queue for waiting takes */
//佇列非空條件,以便通知佇列進行取元素
private final Condition notEmpty = takeLock.newCondition();
/** Lock held by put, offer, etc */
//插入鎖,在 put, offer等方法時會請求
private final ReentrantLock putLock = new ReentrantLock();
/** Wait queue for waiting puts */
//佇列非空條件,以便同意佇列進行插入元素
private final Condition notFull = putLock.newCondition();
signalNotEmpty連結串列非空,然後signal(通知) takeLock進行獲取元素
//僅在put/offer後呼叫
private void signalNotEmpty() {
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();//強制拿鎖
try {
notEmpty.signal();//觸發signal
} finally {
takeLock.unlock();
}
}
signalNotFull連結串列非滿,然後signal(通知) putLock進行插入元素
//僅在take/poll後呼叫
private void signalNotFull() {
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
notFull.signal();
} finally {
putLock.unlock();
}
}
enqueue插入元素
private void enqueue(Node<E> node) {
// assert putLock.isHeldByCurrentThread();
//putLock必須獲取當前鎖
// assert last.next == null;
//佇列尾必須為空
//新node指向原佇列尾元素的next(鏈下個物件),然後再指向last(鏈尾)
last = last.next = node;
}
dequeue取元素
private E dequeue() {
// assert takeLock.isHeldByCurrentThread();
//當前執行緒必須持有takeLock
// assert head.item == null;
//當前鏈頭元素必須為空
//備份鏈頭
Node<E> h = head;
//備份鏈次元素(實際要取出的元素,定義為first)
Node<E> first = h.next;
h.next = h; // help GC //原鏈頭h已經無作用
head = first;//first指向head,first成為新鏈頭
E x = first.item;//取出目標元素
first.item = null;//置空(LinkBlockingQueue規範)
return x;
}
fullyLock&fullyUnlock全域性拿鎖和放鎖
void fullyLock() {
putLock.lock();
takeLock.lock();
}
void fullyUnlock() {
takeLock.unlock();
putLock.unlock();
}
Collection插入到佇列
public LinkedBlockingQueue(Collection<? extends E> c) {
this(Integer.MAX_VALUE);//預設無界佇列
//獲取pulLock,建構函式中pulLock從無競爭,但需要保證可見性
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();
}
}
put放入物件
public void put(E e) throws InterruptedException {
//不支援空物件
if (e == null) throw new NullPointerException();
// Note: convention in all put/take/etc is to preset local var
// holding count negative to indicate failure unless set.
//預建立操作標記(-1即無操作)
int c = -1;
//建立節點
Node<E> node = new Node<E>(e);
//備份(副本)putLock和當前總量
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
//請求putLock鎖(可打斷)
putLock.lockInterruptibly();
try {
/*
* Note that count is used in wait guard even though it is
* not protected by lock. This works because count can
* only decrease at this point (all other puts are shut
* out by lock), and we (or some other waiting put) are
* signalled if it ever changes from capacity. Similarly
* for all other uses of count in other wait guards.
*/
//容量已滿則等待
while (count.get() == capacity) {
notFull.await();
}
//執行過插入至鏈尾
enqueue(node);
//原子自增一位,返回舊值
c = count.getAndIncrement();
//連結串列還沒有滿,通知其他執行緒執行插入
if (c + 1 < capacity)
notFull.signal();
} finally {
//釋放鎖
putLock.unlock();
}
if (c == 0) // 由於存在放鎖和拿鎖,這裡可能拿鎖一直在消費資料,count會變化。這裡的if條件表示如果佇列中還有1條資料
signalNotEmpty(); // 在拿鎖的條件物件notEmpty上喚醒正在等待的1個執行緒,表示佇列裡還有1條資料,可以進行消費
}
offer帶時間限制的插入,返回操作結果
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
//嚴禁非空物件
if (e == null) throw new NullPointerException();
//獲取等待時間
long nanos = unit.toNanos(timeout);
//預建立操作標記(-1即無操作)
int c = -1;
//獲取putLock鎖和當前連結串列容量
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
//可打斷的請求鎖
putLock.lockInterruptibly();
try {
//如果已滿載,並且
while (count.get() == capacity) {
if (nanos <= 0)
return false;
//等待nanos(毫秒)秒,期間收到signal則返回(nanos-等待時間),否則在等待結束後返回0或負數
//可打斷並返回InterruptedException
nanos = notFull.awaitNanos(nanos);
}
enqueue(new Node<E>(e));//插入元素
c = count.getAndIncrement();//獲取最新容量高
if (c + 1 < capacity)//未滿載則通知其他執行緒進行put/offer
notFull.signal();
} finally {
putLock.unlock();
}
//存在takeLock和putlock,takeLock可能在消費,count會變化,c == 0表示佇列有一條資料待消費
if (c == 0)//takeLock的條件物件notEmpty上喚醒正在等待的1個執行緒,表示佇列裡還有1條資料,可以進行消費
signalNotEmpty();
return true;
}
offer嘗試插入(一旦嘗試插入則一直等待直至成功)
public boolean offer(E e) {
//元素不能為空
if (e == null) throw new NullPointerException();
//當前連結串列容量
final AtomicInteger count = this.count;
//滿的話則返回false
if (count.get() == capacity)
return false;
//預建立操作標記(-1即無操作)
int c = -1;
Node<E> node = new Node<E>(e);
//獲取putlock
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)//存在takeLock和putlock,takeLock可能在消費,count會變化,c == 0表示佇列有一條資料待消費
signalNotEmpty();//takeLock的條件物件notEmpty上喚醒正在等待的1個執行緒,表示佇列裡還有1條資料,可以進行消費
return c >= 0;//連結串列有元素則表示插入成功
}
take取元素(可打斷)
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();
}
//取出首元素(first) E
x = dequeue();
c = count.getAndDecrement();//連結串列容量(原子)減一,並返回舊值
//連結串列非空則繼續通知其他執行緒來取
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();//放鎖
}
//如果鏈滿則通知其他putLock等待的執行緒進行取元素
//意思是,takeLock和putLock同時進行時,putLock一直在放元素,true表示有一條執行緒在等待插入元素
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)//如果鏈長度大於1,證明還有鏈還有元素,通知其他等待的takeLock執行取元素
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)//原鏈長度達至最大長度,即在取完元素後還可以放一個元素,所以執行通知putLock進行放元素
signalNotFull();
return x;
}
poll取元素
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;
}
peek取元素,但不拆鏈
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();
}
}
unlink 拆鏈,將trail的下個元素p從鏈中拆除
void unlink(Node<E> p, Node<E> trail) {
// assert isFullyLocked();//必須獲takeLock和putLock,合稱fullyLock();
// p.next is not changed, to allow iterators that are
// traversing p to maintain their weak-consistency guarantee.
p.item = null;//p元素item置null
trail.next = p.next;//trail和(p.next)建立鏈關係
//如果原p就是尾元素,則置trail為尾元素
if (last == p)
last = trail;
//獲取原鏈長度並減一,原鏈長度等於限額則表示鏈未滿,則通知進行插入
if (count.getAndDecrement() == capacity)
notFull.signal();
}
remove拆除item所在的鏈
public boolean remove(Object o) {
//LinkedBlockingQueue允許null的item,除了head和last
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();
}
}
contains o是否存在連結串列中
public boolean contains(Object o) {
if (o == null) return false;
fullyLock();
try {
//p為空則表示到達鏈尾,否則原本就是空鏈
for (Node<E> p = head.next; p != null; p = p.next)
if (o.equals(p.item))
return true;
return false;
} finally {
fullyUnlock();
}
}
toArray迭代元素返回陣列
public Object[] toArray() {
fullyLock();//獲取全域性鎖
try {
int size = count.get();
Object[] a = new Object[size];
int k = 0;
for (Node<E> p = head.next; p != null; p = p.next)
a[k++] = p.item;
return a;
} finally {
fullyUnlock();
}
}
toArray迭代元素,然後插入陣列a
public <T> T[] toArray(T[] a) {
fullyLock();//獲取全鎖
try {
int size = count.get();//當前連結串列長度
if (a.length < size)//引數陣列a長度小於當前連結串列長度,則進行擴容
a = (T[])java.lang.reflect.Array.newInstance
(a.getClass().getComponentType(), size);
int k = 0;//迭代下標
//迭代連結串列並且將item存入陣列a
for (Node<E> p = head.next; p != null; p = p.next)
a[k++] = (T)p.item;
//如果引數陣列a長度長於鏈長度,則a下標的元素置空,但(k+1)往後的元素呢?又不置空?
if (a.length > k)
a[k] = null;
return a;
} finally {
fullyUnlock();
}
}
toString
public String toString() {
fullyLock();//全域性鎖
try {
Node<E> p = head.next;//獲取首元素,為空則直接返回[]
if (p == null)
return "[]";
StringBuilder sb = new StringBuilder();
sb.append(`[`);
for (;;) {
E e = p.item;//獲取元素,然後組裝,如果item為當前連結串列則返回this Collection
sb.append(e == this ? "(this Collection)" : e);
p = p.next;//為空則到達鏈尾
if (p == null)
return sb.append(`]`).toString();
sb.append(`,`).append(` `);
}
} finally {
fullyUnlock();
}
}
clear清空鏈
public void clear() {
fullyLock();//全域性鎖
try {
//1,取出實際頭元素p,備份原head至h 4,將p定於為新head
for (Node<E> p, h = head; (p = h.next) != null; h = p) {
h.next = h;//2,原head的next指向原head,造成循壞鏈,並item為空
p.item = null;//3,實際頭元素item置空,help gc
}
head = last;
// assert head.item == null && head.next == null;
if (count.getAndSet(0) == capacity)
notFull.signal();
} finally {
fullyUnlock();
}
}
drainTo轉換item至Collection
public int drainTo(Collection<? super E> c, int maxElements) {
//集合不能為空並不能為當前元素
if (c == null)
throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
if (maxElements <= 0)
return 0;
boolean signalNotFull = false;//是否未滿,以通知來插入
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();//請求tackLock
try {
//maxElements和count,取小的一方
int n = Math.min(maxElements, count.get());
// count.get provides visibility to first n Nodes
Node<E> h = head;
int i = 0;
try {
//迭代鏈
while (i < n) {
//取出節點head次元素
Node<E> p = h.next;
//新增至collections
c.add(p.item);
//然後置空
p.item = null;
//原head自關聯
h.next = h;
//定義新head
h = p;
++i;
}
return n;
} finally {
// Restore invariants even if c.add() threw
//恢復鏈原有狀態,即使c.add()拋異常
if (i > 0) {//如果已經迭代過元素將迭代中的h作為新head
//assert h.item == null;
head = h;
//如果迭代完鏈的原長度的為capacity(鏈容量最大值)則表示此鏈沒有滿,通知putlock進行插入
signalNotFull = (count.getAndAdd(-i) == capacity);
}
}
} finally {
takeLock.unlock();
if (signalNotFull)
signalNotFull();
}
}
Itr迭代器
private class Itr implements Iterator<E> {
/*
* Basic weakly-consistent iterator. At all times hold the next
* item to hand out so that if hasNext() reports true, we will
* still have it to return even if lost race with a take etc.
*/
private Node<E> current;
private Node<E> lastRet;
private E currentElement;
//建構函式
Itr() {
fullyLock();
try {//下個元素
current = head.next;
//下個元素item
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<E> nextNode(Node<E> p) {
for (;;) {
Node<E> s = p.next;
//如果自連鏈,則證明鏈頭(clear()和drainTo()回導致此情況)
if (s == p)
return head.next;
//否則返回p.next(s != null && s.item == null僅在鏈頭時發生)
if (s == null || s.item != null)
return s;
p = s;
}
}
public E next() {
fullyLock();
try {
//hasNext已經判斷了不為空
if (current == null)
throw new NoSuchElementException();
E x = currentElement;
lastRet = current;
current = nextNode(current);
//current == null表示已經達到鏈尾
currentElement = (current == null) ? null : current.item;
return x;
} finally {
fullyUnlock();
}
}
public void remove() {
//hasNext已經判斷了不為空
if (lastRet == null)
throw new IllegalStateException();
fullyLock();
try {
Node<E> node = lastRet;
lastRet = null;
for (Node<E> trail = head, p = trail.next;
p != null;
trail = p, p = p.next) {
//迭代鏈,找到p然後拆鏈
if (p == node) {
unlink(p, trail);
break;
}
}
} finally {
fullyUnlock();
}
}
}
相關文章
- LinkedBlockingQueue 原始碼解析BloC原始碼
- LinkedBlockingQueue中put原始碼分析BloC原始碼
- PostgreSQL 原始碼解讀(3)- 如何閱讀原始碼SQL原始碼
- WeakHashMap,原始碼解讀HashMap原始碼
- Handler原始碼解讀原始碼
- Laravel 原始碼解讀Laravel原始碼
- Swoft 原始碼解讀原始碼
- SDWebImage原始碼解讀Web原始碼
- MJExtension原始碼解讀原始碼
- Masonry原始碼解讀原始碼
- HashMap原始碼解讀HashMap原始碼
- Redux原始碼解讀Redux原始碼
- require() 原始碼解讀UI原始碼
- ZooKeeper原始碼解讀原始碼
- FairyGUI原始碼解讀AIGUI原始碼
- 【C++】【原始碼解讀】std::is_same函式原始碼解讀C++原始碼函式
- vuex 原始碼:原始碼系列解讀總結Vue原始碼
- Laravel 原始碼的解讀Laravel原始碼
- reselect原始碼解讀原始碼
- ThreadLocal 原始碼解讀thread原始碼
- Redux原始碼完全解讀Redux原始碼
- Seajs原始碼解讀JS原始碼
- Axios 原始碼解讀iOS原始碼
- HashMap原始碼個人解讀HashMap原始碼
- Vue原始碼解讀一Vue原始碼
- Slim 框架原始碼解讀框架原始碼
- ReentrantLock原始碼解讀ReentrantLock原始碼
- MJRefresh原始碼解讀原始碼
- GetBean原始碼全面解讀Bean原始碼
- LifeCycle原始碼解讀原始碼
- LinkedHashMap原始碼解讀HashMap原始碼
- ConcurrentHashMap原始碼解讀HashMap原始碼
- Disruptor-原始碼解讀原始碼
- webpack bootstrap原始碼解讀Webboot原始碼
- Kafka Eagle 原始碼解讀Kafka原始碼
- ThreadLocal原始碼解讀thread原始碼
- Masonry 原始碼解讀(上)原始碼
- Masonry 原始碼解讀(下)原始碼