您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“通過Java源碼解析阻塞隊列ArrayBlockingQueue”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“通過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方法才會返回。
到此,相信大家對“通過Java源碼解析阻塞隊列ArrayBlockingQueue”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關內(nèi)容可以進入相關頻道進行查詢,關注我們,繼續(xù)學習!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。