欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java并發(fā)中DelayQueue延遲隊(duì)列原理剖析

 更新時(shí)間:2021年06月08日 09:56:10   作者:BattleHeart  
DelayQueue隊(duì)列是一個(gè)延遲隊(duì)列,本文將結(jié)合實(shí)例代碼,詳細(xì)的介紹DelayQueue延遲隊(duì)列的源碼分析,感興趣的小伙伴們可以參考一下

介紹

DelayQueue隊(duì)列是一個(gè)延遲隊(duì)列,DelayQueue中存放的元素必須實(shí)現(xiàn)Delayed接口的元素,實(shí)現(xiàn)接口后相當(dāng)于是每個(gè)元素都有個(gè)過期時(shí)間,當(dāng)隊(duì)列進(jìn)行take獲取元素時(shí),先要判斷元素有沒有過期,只有過期的元素才能出隊(duì)操作,沒有過期的隊(duì)列需要等待剩余過期時(shí)間才能進(jìn)行出隊(duì)操作。

源碼分析

DelayQueue隊(duì)列內(nèi)部使用了PriorityQueue優(yōu)先隊(duì)列來進(jìn)行存放數(shù)據(jù),它采用的是二叉堆進(jìn)行的優(yōu)先隊(duì)列,使用ReentrantLock鎖來控制線程同步,由于內(nèi)部元素是采用的PriorityQueue來進(jìn)行存放數(shù)據(jù),所以Delayed接口實(shí)現(xiàn)了Comparable接口,用于比較來控制優(yōu)先級,如下代碼所示:

 public interface Delayed extends Comparable<Delayed> {
 
     /**
      * Returns the remaining delay associated with this object, in the
      * given time unit.
      *
      * @param unit the time unit
      * @return the remaining delay; zero or negative values indicate
      * that the delay has already elapsed
     */
    long getDelay(TimeUnit unit);
}

DelayQueue的成員變量如下所示:

 // 鎖。
 private final transient ReentrantLock lock = new ReentrantLock();
 // 優(yōu)先隊(duì)列。
 private final PriorityQueue<E> q = new PriorityQueue<E>();
 
 /**
  * Leader-Follower的變種。
  * Thread designated to wait for the element at the head of
  * the queue.  This variant of the Leader-Follower pattern
 * (http://www.cs.wustl.edu/~schmidt/POSA/POSA2/) serves to
 * minimize unnecessary timed waiting.  When a thread becomes
 * the leader, it waits only for the next delay to elapse, but
 * other threads await indefinitely.  The leader thread must
 * signal some other thread before returning from take() or
 * poll(...), unless some other thread becomes leader in the
 * interim.  Whenever the head of the queue is replaced with
 * an element with an earlier expiration time, the leader
 * field is invalidated by being reset to null, and some
 * waiting thread, but not necessarily the current leader, is
 * signalled.  So waiting threads must be prepared to acquire
 * and lose leadership while waiting.
 */
private Thread leader = null;

/**
 * Condition signalled when a newer element becomes available
 * at the head of the queue or a new thread may need to
 * become leader.
 */
// 條件,代表如果有數(shù)據(jù)則通知Follower線程,喚醒線程處理隊(duì)列內(nèi)容。
private final Condition available = lock.newCondition();

Leader-Follower模式的變種,用于最小化不必要的定時(shí)等待,當(dāng)一個(gè)線程被選擇為Leader時(shí),它會(huì)等待延遲過去執(zhí)行代碼邏輯,而其他線程則需要無限期等待,在從take或poll返回之前,每當(dāng)隊(duì)列的頭部被替換為具有更早到期時(shí)間的元素時(shí),leader字段將通過重置為空而無效,Leader線程必須向其中一個(gè)Follower線程發(fā)出信號,被喚醒的 follwer 線程被設(shè)置為新的Leader 線程。

offer操作

 public boolean offer(E e) {
     // 獲取到鎖
     final ReentrantLock lock = this.lock;
     lock.lock();
     try {
         // 將元素存儲(chǔ)到PriorityQueue優(yōu)先隊(duì)列中
         q.offer(e);
         // 如果第一個(gè)元素是當(dāng)前元素,說明之前隊(duì)列中為空,則先將Leader設(shè)置為空,通知等待線程可以爭搶Leader了。
         if (q.peek() == e) {
            leader = null;
            available.signal();
        }
        // 返回成功
        return true;
    } finally {
        lock.unlock();
    }
}

offer操作前先進(jìn)行獲取鎖的操作,也就是同一時(shí)間內(nèi)只能有一個(gè)線程可以入隊(duì)操作。

  • 獲取到ReentrantLock鎖對象。
  • 將元素添加到PriorityQueue優(yōu)先隊(duì)列中
  • 如果隊(duì)列中最早過期的元素是自己,則說明隊(duì)列原先是空的,所以將Leader進(jìn)行重置,通知Follower線程可以成為Leader線程。
  • 最后進(jìn)行解鎖操作。

put操作

put操作其實(shí)就是調(diào)用的offer操作來進(jìn)行添加數(shù)據(jù)的,以下是源碼信息:

public void put(E e) {
    offer(e);
}

take操作

 public E take() throws InterruptedException {
     final ReentrantLock lock = this.lock;
     // 獲取可中斷的鎖。
     lock.lockInterruptibly();
     try {
         // 循環(huán)獲取數(shù)據(jù)。
         for (;;) {
             // 獲取最早過期的元素,但是不彈出對象。
             E first = q.peek();
            // 如果最早過期的元素為空,說明隊(duì)列為空,則線程直接進(jìn)入無限期等待,并且讓出鎖。
            if (first == null)
                // 當(dāng)前線程無限期等待,直到被喚醒,并且讓出鎖對象。
                available.await();
            else {
                // 獲取最早過期的元素剩余過期時(shí)間。
                long delay = first.getDelay(NANOSECONDS);
                // 如果剩余過期時(shí)間小于0,則說明已經(jīng)過期,反之還沒有過期。
                if (delay <= )
                    // 如果已經(jīng)過期直接獲取最早過期的元素,并返回。
                    return q.poll();
                // 如果剩余過期日期大于0,則會(huì)進(jìn)入到這里。
                // 將剛才獲取的最早過期的元素設(shè)置為空。
                first = null; // don't retain ref while waiting
                // 如果有線程爭搶的Leader線程,則進(jìn)行無限期等待。
                if (leader != null)
                    // 無限期等待并讓出鎖。
                    available.await();
                else {
                    // 獲取當(dāng)前線程。
                    Thread thisThread = Thread.currentThread();
                    // 設(shè)置當(dāng)前線程變?yōu)長eader線程。
                    leader = thisThread;
                    try {
                        // 等待剩余等待時(shí)間。
                        available.awaitNanos(delay);
                    } finally {
                        // 將Leader設(shè)置為null。
                        if (leader == thisThread)
                            leader = null;
                    }
                }
            }
        }
    } finally {
        // 如果隊(duì)列不為空,并且沒有Leader則通知等待線程可以成為Leader。
        if (leader == null && q.peek() != null)
            // 通知等待線程。
            available.signal();
        lock.unlock();
    }
}
  1. 當(dāng)獲取元素時(shí),先獲取到鎖對象。
  2. 獲取最早過期的元素,但是并不從隊(duì)列中彈出元素。
  3. 最早過期元素是否為空,如果為空則直接讓當(dāng)前線程無限期等待狀態(tài),并且讓出當(dāng)前鎖對象。
  4. 如果最早過期的元素不為空
    1. 獲取最早過期元素的剩余過期時(shí)間,如果已經(jīng)過期則直接返回當(dāng)前元素
    2. 如果沒有過期,也就是說剩余時(shí)間還存在,則先獲取Leader對象,如果Leader已經(jīng)有線程在處理,則當(dāng)前線程進(jìn)行無限期等待,如果Leader為空,則首先將Leader設(shè)置為當(dāng)前線程,并且讓當(dāng)前線程等待剩余時(shí)間。
    3. 最后將Leader線程設(shè)置為空
  5. 如果Leader已經(jīng)為空,并且隊(duì)列有內(nèi)容則喚醒一個(gè)等待的隊(duì)列。

poll操作

獲取最早過期的元素,如果隊(duì)列頭沒有過期的元素則直接返回null,反之返回過期的元素。

 public E poll() {
     final ReentrantLock lock = this.lock;
     lock.lock();
     try {
         E first = q.peek();
         // 如果隊(duì)列為空或者隊(duì)列最早過期的元素沒有過期,則返回null。
         if (first == null || first.getDelay(NANOSECONDS) > 0)
             return null;
         else
            // 出隊(duì)列操作。
            return q.poll();
    } finally {
        lock.unlock();
    }
}

小結(jié)

  • DelayQueue是一個(gè)無界的并發(fā)延遲阻塞隊(duì)列,隊(duì)列中的元素必須實(shí)現(xiàn)Delayed接口,相應(yīng)了需要實(shí)現(xiàn)Comparable接口實(shí)現(xiàn)比較的方法
  • Leader-Follower模式的變種,用于最小化不必要的定時(shí)等待,當(dāng)一個(gè)線程被選擇為Leader時(shí),它會(huì)等待延遲過去執(zhí)行代碼邏輯,而其他線程則需要無限期等待,在從take或poll返回之前,每當(dāng)隊(duì)列的頭部被替換為具有更早到期時(shí)間的元素時(shí),leader字段將通過重置為空而無效,Leader線程必須向其中一個(gè)Follower線程發(fā)出信號,被喚醒的 follwer 線程被設(shè)置為新的Leader 線程。

到此這篇關(guān)于java并發(fā)中DelayQueue延遲隊(duì)列原理剖析的文章就介紹到這了,更多相關(guān)java DelayQueue延遲隊(duì)列內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springboot-2.3.x最新版源碼閱讀環(huán)境搭建(基于gradle構(gòu)建)

    springboot-2.3.x最新版源碼閱讀環(huán)境搭建(基于gradle構(gòu)建)

    這篇文章主要介紹了springboot-2.3.x最新版源碼閱讀環(huán)境搭建(基于gradle構(gòu)建),需要的朋友可以參考下
    2020-08-08
  • Mybatis Plus Wrapper查詢某幾列的方法實(shí)現(xiàn)

    Mybatis Plus Wrapper查詢某幾列的方法實(shí)現(xiàn)

    MybatisPlus中,使用Wrapper的select和notSelect方法可以精確控制查詢的字段,本文就來介紹一下Mybatis Plus Wrapper查詢某幾列的方法實(shí)現(xiàn),感興趣的可以了解一下
    2024-10-10
  • Java的“Goto”與標(biāo)簽及使用詳解

    Java的“Goto”與標(biāo)簽及使用詳解

    goto在Java中是一個(gè)保留字,但在語言中并沒有用到它;Java沒有g(shù)oto。接下來通過本文給大家介紹Java的“Goto”與標(biāo)簽,感興趣的朋友跟隨小編一起看看吧
    2018-10-10
  • RocketMQ的順序消費(fèi)機(jī)制詳解

    RocketMQ的順序消費(fèi)機(jī)制詳解

    這篇文章主要介紹了RocketMQ的順序消費(fèi)機(jī)制詳解,順序消息是指對于一個(gè)指定的?Topic?,消息嚴(yán)格按照先進(jìn)先出(FIFO)的原則進(jìn)行消息發(fā)布和消費(fèi),即先發(fā)布的消息先消費(fèi),后發(fā)布的消息后消費(fèi),,需要的朋友可以參考下
    2023-10-10
  • JavaWeb開發(fā)之【Tomcat 環(huán)境配置】MyEclipse+IDEA配置教程

    JavaWeb開發(fā)之【Tomcat 環(huán)境配置】MyEclipse+IDEA配置教程

    這篇文章主要介紹了JavaWeb開發(fā)之【Tomcat 環(huán)境配置】MyEclipse+IDEA配置教程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • SpringBoot定制JSON響應(yīng)數(shù)據(jù)的實(shí)現(xiàn)

    SpringBoot定制JSON響應(yīng)數(shù)據(jù)的實(shí)現(xiàn)

    本文主要介紹了SpringBoot定制JSON響應(yīng)數(shù)據(jù)的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-02-02
  • SpringMVC實(shí)現(xiàn)通過郵件找回密碼功能

    SpringMVC實(shí)現(xiàn)通過郵件找回密碼功能

    本篇文章主要介紹的是SpringMVC實(shí)現(xiàn)通過郵件找回密碼功能,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧。
    2016-10-10
  • JavaSE圖像驗(yàn)證碼簡單識(shí)別程序詳解

    JavaSE圖像驗(yàn)證碼簡單識(shí)別程序詳解

    這篇文章主要為大家詳細(xì)介紹了JavaSE圖像驗(yàn)證碼簡單識(shí)別程序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Springboot集成minio實(shí)現(xiàn)文件存儲(chǔ)的實(shí)現(xiàn)代碼

    Springboot集成minio實(shí)現(xiàn)文件存儲(chǔ)的實(shí)現(xiàn)代碼

    MinIO?是一款基于Go語言的高性能對象存儲(chǔ)服務(wù),本文主要介紹了Springboot集成minio實(shí)現(xiàn)文件存儲(chǔ)的實(shí)現(xiàn)代碼,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Java日志API管理最佳實(shí)踐詳解

    Java日志API管理最佳實(shí)踐詳解

    這篇文章主要介紹了Java日志API管理最佳實(shí)踐詳解,記錄日志只是有效地利用日志的第一步,更重要的是如何對程序運(yùn)行時(shí)產(chǎn)生的日志進(jìn)行處理和分析。,需要的朋友可以參考下
    2019-06-06

最新評論