LinkedBlockingQueue原始碼理解

2021-10-07 19:21:26 字數 2967 閱讀 9760

一、類介紹

基於鍊錶實現的fifo阻塞佇列實現類。

二、屬性介紹

//鍊錶節點

static class node

}/** 佇列容量,沒指定時容量為 integer.max_value */

private final int capacity;

/** 佇列內當前元素個數,保證原子性的增減元素 */

private final atomicinteger count = new atomicinteger();

/*** 不是鍊錶的頭結點!不是鍊錶的頭結點!不是鍊錶的頭結點!

* head.next = 煉表頭結點

*/transient nodehead;

/*** 鍊錶尾節點

*/private transient nodelast;

/** 獲取元素時的鎖 */

private final reentrantlock takelock = new reentrantlock();

/** takelock關聯的condition */

private final condition notempty = takelock.newcondition();

/** 儲存元素時的鎖。 */

private final reentrantlock putlock = new reentrantlock();

/** putlock關聯的condition */

private final condition notfull = putlock.newcondition();

三、方法介紹

1、構造器

// 無參構造器,佇列容量是integer.max_value

public linkedblockingqueue()

/*** 建立乙個指定容量的佇列

* 初始化head和tail節點

*/public linkedblockingqueue(int capacity)

/*** 建立容量為integer.max_value的佇列,按傳入的集合的遍歷順序,把集合中元素依次入佇列。

*/public linkedblockingqueue(collection<? extends e> c)

count.set(n); //佇列元素計數

} finally

}

2、寫資料:寫資料入佇列有put()方法、offer()方法以及其過載的超時版本方法。以put方法為例說明,其他的寫資料方法大致差不多。寫資料的方法,在佇列已滿的情況下,會阻塞,直到佇列未滿。

public void put(e e) throws interruptedexception 

//元素入佇列,直接新增到鍊錶末尾

enqueue(node);

//先取資料,再加1

c = count.getandincrement();

//存入資料後,鍊錶仍然未滿,發出鍊錶未滿的通知

if (c + 1 < capacity)

notfull.signal();

} finally

//注意,c是新增元素前的佇列元素數量,當c=0時,新增元素後,佇列的元素數量為1,此時發出佇列非空的通知。

if (c == 0)

signalnotempty();

}//新元素新增到鍊錶尾部

private void enqueue(nodenode)

3、讀資料:讀資料有take()方法、poll()方法和pick()方法以及他們的過載的超時版本。以take方法為例說明。讀資料的方法,在隊列為空的情況下,會進入阻塞狀態。

public e take() throws interruptedexception 

//取佇列頭結點,並刪除佇列的頭結點。

x = dequeue();

//先獲取佇列元素數量,再減1

c = count.getanddecrement();

//如果佇列元素數量大於1,說明此次取元素後,佇列中仍然至少有1個元素,佇列非空,發出非空通知。

//為麼事c != capacity - 1,而是c = capacity? 我覺得是方法末尾仍然用到了c == capacity進行判斷有關,不然,還得把c加1,再與capacity進行比較。

if (c > 1)

notempty.signal();

} finally

//佇列元素再減1之前就等於佇列最大容量,此時,可能又某個寫資料操作,正阻塞著(佇列已滿,等待發出佇列未滿通知),因此在元素數量減1後,需要及時發出佇列未滿通知,讓阻塞的寫執行緒繼續工作。

//這點,也能看出採用兩個鎖的好處了。

if (c == capacity)

signalnotfull();

return x;

}//元素出佇列,這裡只要了解head並不是佇列的第乙個元素就好理解了。

private e dequeue()

4、刪除元素:刪除元素就是普通的鍊錶操作了

//迭代,刪除指定物件。

public boolean remove(object o)

}return false;

} finally

}//利用前置節點,刪除當前節點

void unlink(nodep, nodetrail)

5、方法總結:

1)head並不是佇列的首節點;

2)讀資料時,若資料為空,會觸發讀鎖等待,需要寫資料操作發生後發出佇列非空通知;寫資料時,如果佇列已滿,會觸發寫鎖等待,需要讀資料操作發生後發出佇列未滿通知。

四、鍊錶操作圖

五、思考

1、takelock和putlock:因為入佇列是操作隊尾的元素,而取元素是操作隊首的元素,用兩個鎖,保證執行緒安全的同時,也提高了效能。

Java集合 LinkedList原始碼理解筆記

1.內部類node節點,item儲存資料內容,next prev儲存前後節點,形成鍊錶。private static class node 2.first last屬性字段儲存開始節點和結束節點。pointer to first node.invariant first null last null...

SpringMvc原始碼(二) 處理請求過程

過程 1.請求首先進入到frameworkservlet的processrequest中。2.呼叫dispatcherservlet中的doservice方法,對請求進行預設定,doservice方法在frameworkservlet為抽象方法。3.最後呼叫dispatcherservlet的dod...

SpringMvc原始碼(二) 處理請求過程

過程 1.請求首先進入到frameworkservlet的processrequest中。2.呼叫dispatcherservlet中的doservice方法,對請求進行預設定,doservice方法在frameworkservlet為抽象方法。3.最後呼叫dispatcherservlet的dod...