一、類介紹
基於鍊錶實現的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...