Java源碼解析阻塞隊(duì)列ArrayBlockingQueue介紹
Java的阻塞隊(duì)列,在實(shí)現(xiàn)時(shí),使用到了lock和condition,下面是對其主要方法的介紹。
首先看一下,阻塞隊(duì)列中使用到的鎖。
/** Main lock guarding all access **/ final ReentrantLock lock; /** Condition for waiting takes **/ private final Condition notEmpty; /** Condition for waiting puts **/ private final Condition notFull;
主要的鎖是一個可重入鎖,根據(jù)注釋,它是用來保證所有訪問的同步。此外,還有2個condition,notEmpty用于take等待,notFull用于put等待。
兩個condition的初始化方法如下:
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
下面介紹一下put方法。代碼如下。
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
notFull.await();
enqueue(e);
} finally {
lock.unlock();
}
}
進(jìn)行put時(shí),首先對待插入的元素進(jìn)行了非null判斷。然后獲取鎖。之后用一個循環(huán)進(jìn)行判斷,如果元素已滿,那么,就調(diào)用notFull的await方法,進(jìn)行阻塞。當(dāng)有別的線程(其實(shí)是take元素的線程)調(diào)用notFull的siginal方法后,put線程會被喚醒。喚醒后再確認(rèn)一下count是否小于items.length,如果是,則進(jìn)行加入隊(duì)列的操作。
下面介紹一下take方法,代碼如下:
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
進(jìn)行take時(shí),同樣先要獲取鎖,然后判斷元素個數(shù)是否為0,為0時(shí)需要等待在notEmpty條件上,等待被喚醒。喚醒之后,會再進(jìn)行一次元素個數(shù)判斷,然后進(jìn)行出隊(duì)列操作。
分析代碼到這里的時(shí)候,我產(chǎn)生了一個疑問,如果當(dāng)前隊(duì)列慢了,執(zhí)行put的線程在獲取到鎖之后,等待notFull條件上。那么,當(dāng)執(zhí)行take操作的線程想獲取鎖時(shí),阻塞隊(duì)列的鎖已經(jīng)被前面put的線程獲取了,那么take將永遠(yuǎn)得不到機(jī)會執(zhí)行。怎么回事呢?
后來,我查了condition的await方法,它的注釋如下:
- Causes the current thread to wait until it is signalled or interrupted.
- The lock associated with this Condition is atomically released and the current thread becomes disabled for thread scheduling purposes and lies dormant until one of four things happens......
原因在await方法的作用上。因?yàn)閏ondition是通過lock創(chuàng)建的,而調(diào)用condition的await方法時(shí),會自動釋放和condition關(guān)聯(lián)的鎖。所以說,當(dāng)put線程被阻塞后,它實(shí)際已經(jīng)釋放了鎖了。所以,當(dāng)有take線程想執(zhí)行時(shí),它是可以獲取到鎖的。
另一個問題:當(dāng)?shù)却赾ondition上的線程被喚醒時(shí),因?yàn)橹罢{(diào)用await前,已經(jīng)獲取了鎖,那么被喚醒時(shí),它是自動就擁有了鎖,還是需要重新獲取呢?
在await方法的注釋中,有如下的一段話:
- In all cases, before this method can return the current thread must re-acquire the lock associated with this condition. When the thread returns it is guaranteed to hold this lock.
說明當(dāng)?shù)却赾ondition上的線程被喚醒時(shí),它需要重新獲取condition關(guān)聯(lián)的鎖,獲取到之后,await方法才會返回。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請查看下面相關(guān)鏈接
- java ArrayBlockingQueue阻塞隊(duì)列的實(shí)現(xiàn)示例
- Java中ArrayBlockingQueue和LinkedBlockingQueue
- Java 并發(fā)編程ArrayBlockingQueue的實(shí)現(xiàn)
- java ArrayBlockingQueue的方法及缺點(diǎn)分析
- Java源碼解析阻塞隊(duì)列ArrayBlockingQueue常用方法
- Java源碼解析阻塞隊(duì)列ArrayBlockingQueue功能簡介
- 詳細(xì)分析Java并發(fā)集合ArrayBlockingQueue的用法
- java并發(fā)之ArrayBlockingQueue詳細(xì)介紹
- Java并發(fā)編程ArrayBlockingQueue的使用
相關(guān)文章
在?Spring?Boot?中使用?Quartz?調(diào)度作業(yè)的示例詳解
這篇文章主要介紹了在?Spring?Boot?中使用?Quartz?調(diào)度作業(yè)的示例詳解,在本文中,我們將看看如何使用Quartz框架來調(diào)度任務(wù),Quartz支持在特定時(shí)間運(yùn)行作業(yè)、重復(fù)作業(yè)執(zhí)行、將作業(yè)存儲在數(shù)據(jù)庫中以及Spring集成,需要的朋友可以參考下2022-07-07
一文詳解SpringBoot如何使用pageHelper做分頁處理
分頁是常見大型項(xiàng)目都需要的一個功能,PageHelper是一個非常流行的MyBatis分頁插件,下面就跟隨小編一起來了解下SpringBoot是如何使用pageHelper做分頁處理的吧2025-03-03
Java Swing JLabel標(biāo)簽的使用方法
這篇文章主要介紹了Java Swing JLabel標(biāo)簽的使用方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
java復(fù)制文件的4種方式及拷貝文件到另一個目錄下的實(shí)例代碼
這篇文章主要介紹了java復(fù)制文件的4種方式,通過實(shí)例帶給大家介紹了java 拷貝文件到另一個目錄下的方法,需要的朋友可以參考下2018-06-06

