【Java並發編程】19、DelayQueue源碼分析,delayqueue源碼

來源:互聯網
上載者:User

【Java並發編程】19、DelayQueue源碼分析,delayqueue源碼

DelayQueue,帶有延遲元素的安全執行緒隊列,當非阻塞從隊列中擷取元素時,返回最早達到延遲時間的元素,或空(沒有元素達到延遲時間)。DelayQueue的泛型參數需要實現Delayed介面,Delayed介面繼承了Comparable介面,DelayQueue內部使用非安全執行緒的優先隊列(PriorityQueue),並使用Leader/Followers模式,最小化不必要的等待時間。DelayQueue不允許包含null元素。

領導者/追隨者模式是多個背景工作執行緒輪流獲得事件來源集合,輪流監聽、分發並處理事件的一種模式。在任意時間點,程式都僅有一個領導者線程,它負責監聽IO事件。而其他線程都是追隨者,它們休眠線上程池中等待成為新的領導者。當前的領導者如果檢測到IO事件,首先要從線程池中推選出新的領導者線程,然後處理IO事件。此時,新的領導者等待新的IO事件,而原來的領導者則處理IO事件,二者實現了並發。

 簡單理解,就是最多隻有一個線程在處理,其他線程在睡眠。在DelayQueue的實現中,Leader/Followers模式用於等待隊首的第一個元素。

類定義及參數:

public class DelayQueue<E extends Delayed> extends AbstractQueue<E>    implements BlockingQueue<E> {    /** 重入鎖,實現安全執行緒 */    private final transient ReentrantLock lock = new ReentrantLock();    /** 使用優先隊列實現 */    private final PriorityQueue<E> q = new PriorityQueue<E>();    /** Leader/Followers模式 */    private Thread leader = null;    /** 條件對象,當新元素到達,或新線程可能需要成為leader時被通知 */    private final Condition available = lock.newCondition();

  建構函式:

    /**     * 預設構造,得到空的延遲隊列     */    public DelayQueue() {}    /**     * 構造延遲隊列,初始包含c中的元素     *     * @param c 初始包含的元素集合     * @throws NullPointerException 當集合或集合任一元素為空白時拋出null 指標錯誤     */    public DelayQueue(Collection<? extends E> c) {        this.addAll(c);    }

  add方法:

    /**     * 向延遲隊列插入元素     *     * @param e 要插入的元素     * @return true     * @throws NullPointerException 元素為空白,拋出null 指標錯誤     */    public boolean add(E e) {        // 直接調用offer並返回        return offer(e);    }

  offer方法:

    /**     * 向延遲隊列插入元素     *     * @param e 要插入的元素     * @return true     * @throws NullPointerException 元素為空白,拋出null 指標錯誤     */    public boolean offer(E e) {        final ReentrantLock lock = this.lock;        // 獲得鎖        lock.lock();        try {            // 向優先隊列插入元素            q.offer(e);            // 若在此之前隊列為空白,則置空leader,並通知條件對象,需要結合take方法看            if (q.peek() == e) {                leader = null;                available.signal();            }            return true;        } finally {            // 釋放鎖            lock.unlock();        }    }

  put方法:

    /**     * 向延遲隊列插入元素. 因為隊列是無界的,所以不會阻塞。     *     * @param e 要插入的元素     * @throws NullPointerException 元素為空白,拋出null 指標錯誤     */    public void put(E e) {        offer(e);    }

  帶逾時的offer方法:

    /**     * 向延遲隊列插入元素. 因為隊列是無界的,所以不會阻塞,因此,直接調用offer方法並返回     *     * @param e 要插入的元素     * @param timeout 不會阻塞,忽略     * @param unit 不會阻塞,忽略     * @return true     * @throws NullPointerException 元素為空白,拋出null 指標錯誤     */    public boolean offer(E e, long timeout, TimeUnit unit) {        // 直接調用offer方法並返回        return offer(e);    }

  poll方法:

    /**     * 擷取並移除隊首的元素, 或者返回null(如果隊列不包含到達延遲時間的元素)     *     * @return 隊首的元素, 或者null(如果隊列不包含到達延遲時間的元素)     */    public E poll() {        final ReentrantLock lock = this.lock;        // 獲得鎖        lock.lock();        try {            // 擷取優先隊列隊首元素            E first = q.peek();            // 若優先隊列隊首元素為空白,或者還沒達到延遲時間,返回null            if (first == null || first.getDelay(NANOSECONDS) > 0)                return null;            // 否則,返回並移除隊首元素            else                return q.poll();        } finally {            // 釋放鎖            lock.unlock();        }    }

  take方法(重要):

    /**     * 擷取並移除隊首元素,該方法將阻塞,直到隊列中包含達到延遲時間的元素     *     * @return 隊首元素     * @throws InterruptedException 阻塞時被打斷,拋出打斷異常     */    public E take() throws InterruptedException {        final ReentrantLock lock = this.lock;        // 獲得鎖,該鎖可被打斷        lock.lockInterruptibly();        try {            // 迴圈處理            for (;;) {                // 擷取隊首元素                E first = q.peek();                // 若元素為空白,等待條件,在offer方法中會調用條件對象的通知方法                // 並重新進入迴圈                if (first == null)                    available.await();                // 若元素不為空白                else {                    // 擷取延遲時間                    long delay = first.getDelay(NANOSECONDS);                    // 若達到延遲時間,返回並移除隊首元素                    if (delay <= 0)                        return q.poll();                    // 否則,需要進入等待                    first = null; // 在等待時,不持有引用                    // 若leader不為空白,等待條件                    if (leader != null)                        available.await();                    // 否則,設定leader為當前線程,並逾時等待延遲時間                    else {                        Thread thisThread = Thread.currentThread();                        leader = thisThread;                        try {                            available.awaitNanos(delay);                        } finally {                            if (leader == thisThread)                                leader = null;                        }                    }                }            }        } finally {            // 通知其他線程條件得到滿足            if (leader == null && q.peek() != null)                available.signal();             // 釋放鎖            lock.unlock();        }    }

  帶逾時的poll方法(重要):

    /**     * 擷取並移除隊首元素,該方法將阻塞,直到隊列中包含達到延遲時間的元素或逾時     *     * @return 隊首元素,或者null     * @throws InterruptedException 阻塞等待時被打斷,拋出打斷異常*/    public E poll(long timeout, TimeUnit unit) throws InterruptedException {        long nanos = unit.toNanos(timeout);        final ReentrantLock lock = this.lock;        lock.lockInterruptibly();        try {            for (;;) {                E first = q.peek();                if (first == null) {                    if (nanos <= 0)                        return null;                    else                        nanos = available.awaitNanos(nanos);                } else {                    long delay = first.getDelay(NANOSECONDS);                    if (delay <= 0)                        return q.poll();                    if (nanos <= 0)                        return null;                    first = null; // don't retain ref while waiting                    if (nanos < delay || leader != null)                        nanos = available.awaitNanos(nanos);                    else {                        Thread thisThread = Thread.currentThread();                        leader = thisThread;                        try {                            long timeLeft = available.awaitNanos(delay);                            nanos -= delay - timeLeft;                        } finally {                            if (leader == thisThread)                                leader = null;                        }                    }                }            }        } finally {            if (leader == null && q.peek() != null)                available.signal();            lock.unlock();        }    }

  peek方法:

    /**     * 擷取但不移除隊首元素,或返回null(如果隊列為空白)。和poll方法不同,     * 若隊列不為空白,該方法換回隊首元素,不論是否達到延遲時間     *     * @return 隊首元素,或null(如果隊列為空白)     */    public E peek() {        final ReentrantLock lock = this.lock;        lock.lock();        try {            return q.peek();        } finally {            lock.unlock();        }    }

出處:

https://www.cnblogs.com/enumhack/p/7472873.html

https://www.cnblogs.com/wanly3643/p/3944661.html

jdk源碼

        

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.