Java源碼解析阻塞隊(duì)列ArrayBlockingQueue介紹
Java的阻塞隊(duì)列,在實(shí)現(xiàn)時(shí),使用到了lock和condition,下面是對(duì)其主要方法的介紹。
首先看一下,阻塞隊(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;
主要的鎖是一個(gè)可重入鎖,根據(jù)注釋,它是用來保證所有訪問的同步。此外,還有2個(gè)condition,notEmpty用于take等待,notFull用于put等待。
兩個(gè)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í),首先對(duì)待插入的元素進(jìn)行了非null判斷。然后獲取鎖。之后用一個(gè)循環(huán)進(jìn)行判斷,如果元素已滿,那么,就調(diào)用notFull的await方法,進(jìn)行阻塞。當(dāng)有別的線程(其實(shí)是take元素的線程)調(diào)用notFull的siginal方法后,put線程會(huì)被喚醒。喚醒后再確認(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í),同樣先要獲取鎖,然后判斷元素個(gè)數(shù)是否為0,為0時(shí)需要等待在notEmpty條件上,等待被喚醒。喚醒之后,會(huì)再進(jìn)行一次元素個(gè)數(shù)判斷,然后進(jìn)行出隊(duì)列操作。
分析代碼到這里的時(shí)候,我產(chǎn)生了一個(gè)疑問,如果當(dāng)前隊(duì)列慢了,執(zhí)行put的線程在獲取到鎖之后,等待notFull條件上。那么,當(dāng)執(zhí)行take操作的線程想獲取鎖時(shí),阻塞隊(duì)列的鎖已經(jīng)被前面put的線程獲取了,那么take將永遠(yuǎn)得不到機(jī)會(huì)執(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í),會(huì)自動(dòng)釋放和condition關(guān)聯(lián)的鎖。所以說,當(dāng)put線程被阻塞后,它實(shí)際已經(jīng)釋放了鎖了。所以,當(dāng)有take線程想執(zhí)行時(shí),它是可以獲取到鎖的。
另一個(gè)問題:當(dāng)?shù)却赾ondition上的線程被喚醒時(shí),因?yàn)橹罢{(diào)用await前,已經(jīng)獲取了鎖,那么被喚醒時(shí),它是自動(dòng)就擁有了鎖,還是需要重新獲取呢?
在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方法才會(huì)返回。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(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功能簡(jiǎn)介
- 詳細(xì)分析Java并發(fā)集合ArrayBlockingQueue的用法
- java并發(fā)之ArrayBlockingQueue詳細(xì)介紹
- Java并發(fā)編程ArrayBlockingQueue的使用
相關(guān)文章
SpringCloud使用Zookeeper作為配置中心的示例
這篇文章主要介紹了SpringCloud使用Zookeeper作為配置中心的示例,幫助大家更好的理解和學(xué)習(xí)使用SpringCloud,感興趣的朋友可以了解下2021-04-04Java網(wǎng)絡(luò)編程UDP實(shí)現(xiàn)消息發(fā)送及聊天
這篇文章主要為大家詳細(xì)介紹了Java網(wǎng)絡(luò)編程UDP實(shí)現(xiàn)消息發(fā)送及聊天,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07java設(shè)計(jì)模式-代理模式(實(shí)例講解)
下面小編就為大家?guī)硪黄猨ava設(shè)計(jì)模式-代理模式(實(shí)例講解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-09-09Spring中的@Autowired、@Qualifier和@Primary注解詳解
這篇文章主要介紹了Spring中的@Autowired、@Qualifier和@Primary注解詳解,@Autowired?注解,可以對(duì)類成員變量、方法和構(gòu)造函數(shù)進(jìn)行標(biāo)注,完成自動(dòng)裝配的工作,@Autowired?是默認(rèn)根據(jù)?byType?進(jìn)行自動(dòng)裝配的,需要的朋友可以參考下2023-11-11Spring boot通過HttpSessionListener監(jiān)聽器統(tǒng)計(jì)在線人數(shù)的實(shí)現(xiàn)代碼
這篇文章主要介紹了Spring boot通過HttpSessionListener監(jiān)聽器統(tǒng)計(jì)在線人數(shù)的實(shí)現(xiàn)代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-02-02Spring數(shù)據(jù)庫(kù)多數(shù)據(jù)源路由配置過程圖解
這篇文章主要介紹了Spring數(shù)據(jù)庫(kù)多數(shù)據(jù)源路由配置過程圖解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06Java多線程 兩階段終止模式Two-Phase Termination Patter
這篇文章主要介紹了Java多線程 兩階段終止模式Two-Phase Termination Patter,該模式有兩個(gè)角色,分別是Terminator,終止者,負(fù)責(zé)接收終止請(qǐng)求,執(zhí)行終止處理,處理完成后再終止自己。TerminationRequester終止請(qǐng)求發(fā)出者,用來向Terminator發(fā)出終止請(qǐng)求,需要的朋友可以參考一下2021-10-10