java的阻塞隊列,在實現時,使用到了lock和condition,下面是對其主要方法的介紹。
首先看一下,阻塞隊列中使用到的鎖。
1
2
3
4
5
6
|
/** main lock guarding all access **/ final reentrantlock lock;? /** condition for waiting takes **/ private final condition notempty;? /** condition for waiting puts **/ private final condition notfull; |
主要的鎖是一個可重入鎖,根據注釋,它是用來保證所有訪問的同步。此外,還有2個condition,notempty用于take等待,notfull用于put等待。
兩個condition的初始化方法如下:
1
2
3
4
5
6
7
8
|
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方法。代碼如下。
1
2
3
4
5
6
7
8
9
10
11
12
|
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判斷。然后獲取鎖。之后用一個循環進行判斷,如果元素已滿,那么,就調用notfull的await方法,進行阻塞。當有別的線程(其實是take元素的線程)調用notfull的siginal方法后,put線程會被喚醒。喚醒后再確認一下count是否小于items.length,如果是,則進行加入隊列的操作。
下面介紹一下take方法,代碼如下:
1
2
3
4
5
6
7
8
9
10
11
|
public e take() throws interruptedexception { final reentrantlock lock = this .lock; lock.lockinterruptibly(); try { while (count == 0 ) notempty.await(); return dequeue(); } finally { lock.unlock(); } } |
進行take時,同樣先要獲取鎖,然后判斷元素個數是否為0,為0時需要等待在notempty條件上,等待被喚醒。喚醒之后,會再進行一次元素個數判斷,然后進行出隊列操作。
分析代碼到這里的時候,我產生了一個疑問,如果當前隊列慢了,執行put的線程在獲取到鎖之后,等待notfull條件上。那么,當執行take操作的線程想獲取鎖時,阻塞隊列的鎖已經被前面put的線程獲取了,那么take將永遠得不到機會執行。怎么回事呢?
后來,我查了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創建的,而調用condition的await方法時,會自動釋放和condition關聯的鎖。所以說,當put線程被阻塞后,它實際已經釋放了鎖了。所以,當有take線程想執行時,它是可以獲取到鎖的。
另一個問題:當等待在condition上的線程被喚醒時,因為之前調用await前,已經獲取了鎖,那么被喚醒時,它是自動就擁有了鎖,還是需要重新獲取呢?
在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.
說明當等待在condition上的線程被喚醒時,它需要重新獲取condition關聯的鎖,獲取到之后,await方法才會返回。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對服務器之家的支持。如果你想了解更多相關內容請查看下面相關鏈接
原文鏈接:https://blog.csdn.net/li_canhui/article/details/84100166