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