在 java生產者消費者專題---談談優化(三)中使用了一個鎖對LinkedList進行鎖定,實際可將隊頭和隊尾各用一個鎖,這樣同時添加與移除元素時不會互相競爭,只有同時添加的線程或者同時移除的線程之間纔會互相競爭。核心代碼以下:java
static class Node<T> {
T val;
Node<T> next;優化
public Node(T val) {
super();
this.val = val;
}this
public Node(T val, Node<T> next) {
super();
this.val = val;
this.next = next;
}.net
}線程
private Node<T> headNode;
private Node<T> tailNode;設計
{blog
headNode =tailNode = new Node<T>(null);隊列
}get
現分析隊頭與隊尾節點能夠分別採用不一樣鎖的緣由:源碼
一、一開始take線程將因爲隊列爲空而進入wait狀態,put線程進行正常入隊操做即tailNode=tailNode.next=newNode;
二、通過第一步後隊列中有1個有效元素,且頭節點指向一開始的啞節點,啞節點指向newNode,同時尾節點也指向newNode;
三、此時take線程被激活,與put線程同時處於活動狀態,並假設此時只有一個take線程和一個put線程,它們會同時運行;
四、先說明take一個節點的步驟,因爲頭節點指向啞節點,所以啞節點指向的第一個節點是真正的數據節點,在獲得數據節點的數據後,會將數據節點的數據域置空並將頭節點指向它(此時該數據節點已經充當了新的啞節點角色,原先的啞吧節點會被廢棄,具體能夠看下LinkedBlockingQueue的源代碼)。
五、經過第四步能夠看出take時不會對數據節點的next域產生影響,而put時僅僅對最後一個數據節點的next域產生影響,因此head節點和tail節點能夠採用不一樣的鎖,即take線程和put線程是永遠不會發生競爭的!
啞節點的設計是實現該方法的核心部分,源碼你們就參考LinkedBlockingQueue便可,下篇將分析與ArrayBlockingQueue的效率差別!