java 并發(fā)編程系列文章目錄
1 LinkedBlockingDeque是什么
首先queue是一種數(shù)據(jù)結(jié)構(gòu),一個(gè)集合中,先進(jìn)后出,有兩種實(shí)現(xiàn)的方式,數(shù)組和鏈表。從尾部追加,從頭部獲取。Deque是兩端都可以添加,且兩端都可以獲取,所以它的方法會(huì)有一系列的Last,F(xiàn)rist語義,添加或獲取等操作會(huì)指明哪個(gè)方向的,這也是Deque接口的定義。
那如果你不指定語義 如add()方法,他會(huì)默認(rèn)調(diào)用addLast
綜上所述,LinkedBlockingDeque是一個(gè)線程安全的雙端阻塞隊(duì)列。
2 核心屬性詳解
相對(duì)于LinkedBlockingQueue 他只能使用一把鎖,不能分成put 和 take兩把鎖。因?yàn)榇藭r(shí)雙端都可以put 和 take,所以只能使用一個(gè)鎖,通過鎖,對(duì)其鏈表實(shí)現(xiàn)線程安全的操作。
//隊(duì)列的頭尾節(jié)點(diǎn)
transient Node<E> first;
transient Node<E> last;
//隊(duì)列中元素的數(shù)量
private transient int count;
//指定的隊(duì)列的容量,默認(rèn)Int最大值
private final int capacity;
//實(shí)現(xiàn)線程安全的使用的鎖
final ReentrantLock lock = new ReentrantLock();
//獲取元素的時(shí)候如果空了會(huì)使用它讓其自己等待
private final Condition notEmpty = lock.newCondition();
//添加元素的時(shí)候如果滿了(count == capacity)會(huì)使用它讓其自己等待
private final Condition notFull = lock.newCondition();
3 核心方法詳解
下面會(huì)列舉First系列的方法,因?yàn)閘ast系列相對(duì)于first只是鏈表方向不一樣,操作都是一致的。
3.1 addFirst(E e)
調(diào)用offerFirst 如果未成功 則拋出異常
public void addFirst(E e) {
if (!offerFirst(e))
throw new IllegalStateException("Deque full");
}
3.2 offerFirst(E e)
在鏈表的頭部添加一個(gè)元素,使用ReentrantLock 保證線程安全
public boolean offerFirst(E e) {
if (e == null) throw new NullPointerException();
Node<E> node = new Node<E>(e);
//獲取鎖
final ReentrantLock lock = this.lock;
lock.lock();
try {
//把當(dāng)前元素對(duì)應(yīng)的節(jié)點(diǎn)放到頭結(jié)點(diǎn)那里
return linkFirst(node);
} finally {
lock.unlock();
}
}
private boolean linkFirst(Node<E> node) {
//如果元素已經(jīng)超出容量,返回添加失敗
if (count >= capacity)
return false;
//鏈表的操作,用的是雙向鏈表,first變成自己,之前的first是自己的next
Node<E> f = first;
node.next = f;
first = node;
if (last == null)
last = node;
else
f.prev = node;
//元素統(tǒng)計(jì)數(shù)量加1
++count;
//喚醒那些因?yàn)楂@取不到元素而阻塞的線程
notEmpty.signal();
return true;
}
3.3 putFirst(E e)
相對(duì)于offer一個(gè)元素 如果元素?cái)?shù)量已到達(dá)容量上線,會(huì)阻塞住等待元素被取走才放入
在juc下面 put add take等語義都是一致的
public void putFirst(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
Node<E> node = new Node<E>(e);
//獲取鎖
final ReentrantLock lock = this.lock;
lock.lock();
try {
//添加失敗就阻塞住等待喚醒
while (!linkFirst(node))
notFull.await();
} finally {
lock.unlock();
}
}
3.4 removeFirst()
從頭結(jié)點(diǎn)移除一個(gè)元素,調(diào)用的是pollFirst,拿出元素返回,元素==null會(huì)拋出異常
public E removeFirst() {
E x = pollFirst();
if (x == null) throw new NoSuchElementException();
return x;
}
3.5 pollFirst()
取出first元素并返回,會(huì)返回null
public E pollFirst() {
//加鎖
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 取出first, 鏈表的操作和count的維護(hù)以及喚醒添加元素因?yàn)槿萘康竭_(dá)上線的等待的線程
return unlinkFirst();
} finally {
lock.unlock();
}
}
3.6 takeFirst()
獲取一個(gè)first元素,區(qū)別poll 在于會(huì)阻塞等待
public E takeFirst() throws InterruptedException {
final ReentrantLock lock = this.lock;
//獲取鎖
lock.lock();
try {
E x;
//拿不到就阻塞等待,等待添加元素的時(shí)候被其他線程喚醒
while ( (x = unlinkFirst()) == null)
notEmpty.await();
return x;
} finally {
lock.unlock();
}
}
3.7 其他
對(duì)于last系列方法,只是鏈表的操作方向不一樣而已
其次默認(rèn)的不帶last 和 first系列的方法,即原始的add put等方法,可以等同LinkedBlockingQueue。
LinkedBlockingDeque內(nèi)部是一個(gè)雙向鏈表,支持了鏈表兩端操作,所以方法不一一介紹,原理都是一樣。文章來源:http://www.zghlxwxcb.cn/news/detail-691951.html
4 總結(jié)
LinkedBlockingDeque使用雙端隊(duì)列,通過ReentrantLock保證線程安全,實(shí)現(xiàn)了雙端的線程安全的阻塞隊(duì)列。文章來源地址http://www.zghlxwxcb.cn/news/detail-691951.html
到了這里,關(guān)于java并發(fā)編程 LinkedBlockingDeque詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!