Java BlockingQueue 源碼分析,javablockingqueue

來源:互聯網
上載者:User

Java BlockingQueue 源碼分析,javablockingqueue
簡介

BlockingQueue 是 Java concurrent包提供的多安全執行緒的阻塞隊列,其子類包括 LinkedBlockingQueue 和 ArrayBlockingQueue。

關鍵API

說到隊列,自然少不了首尾的插入刪除操作,BlockingQueue的API中提供了好幾種插入刪除方法。
這些方法在遇到無法滿足的執行條件時,如隊列滿了(添加元素時)/隊列為空白(取出元素時),會採取不同的措施:拋出異常,返回false/null,阻塞調用API的線程,等待一定時間等。具體如下表:

Throws exception Special value Blocks Times out
Insert add(e) offer(e) put(e) offer(e,time,unit)
Remove remove() poll() take() poll(time,unit)
Examine element() peek() not applicable not applicable
ArrayBlockingQueue

ArrayBlockingQueue是一個基於數組的阻塞隊列,在建立一個ArrayBlockingQueue時,需要提供的一個表示隊列大小的參數。

ArrayBlockingQueue是安全執行緒的,但這是怎麼做到的呢?這需要注意類中的三個屬性:

    /** Main lock guarding all access */    final ReentrantLock lock;    /** Condition for waiting takes */    private final Condition notEmpty;    /** Condition for waiting puts */    private final Condition notFull;

這裡一個鎖,兩個條件變數,管理所有使用API的線程的互斥和同步。具體的鎖和條件變數的理論知識,可以參見相關的作業系統書籍。

offer vs put
    public boolean offer(E e) {        checkNotNull(e);        final ReentrantLock lock = this.lock;        lock.lock();        try {            if (count == items.length)                return false;            else {                insert(e);                return true;            }        } finally {            lock.unlock();        }    }    public void put(E e) throws InterruptedException {        checkNotNull(e);        final ReentrantLock lock = this.lock;        lock.lockInterruptibly();        try {            while (count == items.length)                notFull.await();            insert(e);        } finally {            lock.unlock();        }    }

可以看到,兩個方法中在往隊列裡添加元素時,都是先對臨界區加鎖,不同在於,offer方法中若是檢測出隊列已滿,會直接返回false;put方法中,若是檢測出隊列已滿,線程會在 notFull 條件變數中阻塞,這樣線程會釋放鎖,讓其他線程進入臨界區。以後某個時間,一個線程從隊列中取出元素,隊列不再為空白,並且該線程喚醒在notFull條件變數上阻塞的線程,put方法才有可能完成。

poll vs take
 public E take() throws InterruptedException {        final ReentrantLock lock = this.lock;        lock.lockInterruptibly();        try {            while (count == 0)                notEmpty.await();            return extract();        } finally {            lock.unlock();        }    }

take的邏輯和put差不多,只不過這次是若隊列為空白,則線程阻塞在notEmpty 條件變數上,等待其他線程往隊列中添加元素,並喚醒在notEmpty上阻塞的線程。

   public E poll() {        final ReentrantLock lock = this.lock;        lock.lock();        try {            return (count == 0) ? null : extract();        } finally {            lock.unlock();        }    }

poll方法在檢測到隊列為空白時,直接返回null,否則取出隊頭元素。

      public E poll(long timeout, TimeUnit unit) throws InterruptedException {        long nanos = unit.toNanos(timeout);        final ReentrantLock lock = this.lock;        lock.lockInterruptibly();        try {            while (count == 0) {                if (nanos <= 0)                    return null;                nanos = notEmpty.awaitNanos(nanos);            }            return extract();        } finally {            lock.unlock();        }    }

poll 還有個比較有趣的重載實現,這裡利用Condition變數的計時器方法awaitNanos 。先將時間大小根據時間單位換算成納秒的數值,當隊列容量為0是,使用Condition.awaitNanos(…),進行計時,逾時後返回null。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.