您好,登錄后才能下訂單哦!
本篇內容主要講解“通過Java源碼解析阻塞隊列ArrayBlockingQueue”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“通過Java源碼解析阻塞隊列ArrayBlockingQueue”吧!
Java的阻塞隊列,在實現時,使用到了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;
主要的鎖是一個可重入鎖,根據注釋,它是用來保證所有訪問的同步。此外,還有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判斷。然后獲取鎖。之后用一個循環進行判斷,如果元素已滿,那么,就調用notFull的await方法,進行阻塞。當有別的線程(其實是take元素的線程)調用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時,同樣先要獲取鎖,然后判斷元素個數是否為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方法才會返回。
到此,相信大家對“通過Java源碼解析阻塞隊列ArrayBlockingQueue”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。