這篇文章給大家分享的是有關(guān)java集合之ConcurrentLinkedQueue的示例代碼的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

(1)ConcurrentLinkedQueue是阻塞隊列嗎?
(2)ConcurrentLinkedQueue如何保證并發(fā)安全?
(3)ConcurrentLinkedQueue能用于線程池嗎?
ConcurrentLinkedQueue只實現(xiàn)了Queue接口,并沒有實現(xiàn)BlockingQueue接口,所以它不是阻塞隊列,也不能用于線程池中,但是它是線程安全的,可用于多線程環(huán)境中。
那么,它的線程安全又是如何實現(xiàn)的呢?讓我們一起來瞧一瞧。
// 鏈表頭節(jié)點 private transient volatile Node<E> head; // 鏈表尾節(jié)點 private transient volatile Node<E> tail;
就這兩個主要屬性,一個頭節(jié)點,一個尾節(jié)點。
private static class Node<E> {
volatile E item;
volatile Node<E> next;
}典型的單鏈表結(jié)構(gòu),非常純粹。
public ConcurrentLinkedQueue() {
// 初始化頭尾節(jié)點
head = tail = new Node<E>(null);
}
public ConcurrentLinkedQueue(Collection<? extends E> c) {
Node<E> h = null, t = null;
// 遍歷c,并把它元素全部添加到單鏈表中
for (E e : c) {
checkNotNull(e);
Node<E> newNode = new Node<E>(e);
if (h == null)
h = t = newNode;
else {
t.lazySetNext(newNode);
t = newNode;
}
}
if (h == null)
h = t = new Node<E>(null);
head = h;
tail = t;
}這兩個構(gòu)造方法也很簡單,可以看到這是一個×××的單鏈表實現(xiàn)的隊列。
因為它不是阻塞隊列,所以只有兩個入隊的方法,add(e)和offer(e)。
因為是×××隊列,所以add(e)方法也不用拋出異常了。
public boolean add(E e) {
return offer(e);
}
public boolean offer(E e) {
// 不能添加空元素
checkNotNull(e);
// 新節(jié)點
final Node<E> newNode = new Node<E>(e);
// 入隊到鏈表尾
for (Node<E> t = tail, p = t;;) {
Node<E> q = p.next;
// 如果沒有next,說明到鏈表尾部了,就入隊
if (q == null) {
// CAS更新p的next為新節(jié)點
// 如果成功了,就返回true
// 如果不成功就重新取next重新嘗試
if (p.casNext(null, newNode)) {
// 如果p不等于t,說明有其它線程先一步更新tail
// 也就不會走到q==null這個分支了
// p取到的可能是t后面的值
// 把tail原子更新為新節(jié)點
if (p != t) // hop two nodes at a time
casTail(t, newNode); // Failure is OK.
// 返回入隊成功
return true;
}
}
else if (p == q)
// 如果p的next等于p,說明p已經(jīng)被刪除了(已經(jīng)出隊了)
// 重新設(shè)置p的值
p = (t != (t = tail)) ? t : head;
else
// t后面還有值,重新設(shè)置p的值
p = (p != t && t != (t = tail)) ? t : q;
}
}入隊整個流程還是比較清晰的,這里有個前提是出隊時會把出隊的那個節(jié)點的next設(shè)置為節(jié)點本身。
(1)定位到鏈表尾部,嘗試把新節(jié)點放到后面;
(2)如果尾部變化了,則重新獲取尾部,再重試;
因為它不是阻塞隊列,所以只有兩個出隊的方法,remove()和poll()。
public E remove() {
E x = poll();
if (x != null)
return x;
else
throw new NoSuchElementException();
}
public E poll() {
restartFromHead:
for (;;) {
// 嘗試彈出鏈表的頭節(jié)點
for (Node<E> h = head, p = h, q;;) {
E item = p.item;
// 如果節(jié)點的值不為空,并且將其更新為null成功了
if (item != null && p.casItem(item, null)) {
// 如果頭節(jié)點變了,則不會走到這個分支
// 會先走下面的分支拿到新的頭節(jié)點
// 這時候p就不等于h了,就更新頭節(jié)點
// 在updateHead()中會把head更新為新節(jié)點
// 并讓head的next指向其自己
if (p != h) // hop two nodes at a time
updateHead(h, ((q = p.next) != null) ? q : p);
// 上面的casItem()成功,就可以返回出隊的元素了
return item;
}
// 下面三個分支說明頭節(jié)點變了
// 且p的item肯定為null
else if ((q = p.next) == null) {
// 如果p的next為空,說明隊列中沒有元素了
// 更新h為p,也就是空元素的節(jié)點
updateHead(h, p);
// 返回null
return null;
}
else if (p == q)
// 如果p等于p的next,說明p已經(jīng)出隊了,重試
continue restartFromHead;
else
// 將p設(shè)置為p的next
p = q;
}
}
}
// 更新頭節(jié)點的方法
final void updateHead(Node<E> h, Node<E> p) {
// 原子更新h為p成功后,延遲更新h的next為它自己
// 這里用延遲更新是安全的,因為head節(jié)點已經(jīng)變了
// 只要入隊出隊的時候檢查head有沒有變化就行了,跟它的next關(guān)系不大
if (h != p && casHead(h, p))
h.lazySetNext(h);
}出隊的整個邏輯也是比較清晰的:
(1)定位到頭節(jié)點,嘗試更新其值為null;
(2)如果成功了,就成功出隊;
(3)如果失敗或者頭節(jié)點變化了,就重新尋找頭節(jié)點,并重試;
(4)整個出隊過程沒有一點阻塞相關(guān)的代碼,所以出隊的時候不會阻塞線程,沒找到元素就返回null;
感謝各位的閱讀!關(guān)于“java集合之ConcurrentLinkedQueue的示例代碼”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。
本文標(biāo)題:java集合之ConcurrentLinkedQueue的示例代碼-創(chuàng)新互聯(lián)
文章URL:http://chinadenli.net/article12/hddgc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營銷型網(wǎng)站建設(shè)、網(wǎng)站設(shè)計公司、手機網(wǎng)站建設(shè)、搜索引擎優(yōu)化、用戶體驗、微信公眾號
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容