最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中的DelayQueue源碼解析

 更新時(shí)間:2023年12月13日 08:32:59   作者:demon7552003  
這篇文章主要介紹了Java中的DelayQueue源碼解析,一個(gè)實(shí)現(xiàn)PriorityBlockingQueue實(shí)現(xiàn)延遲獲取的無界隊(duì)列,在創(chuàng)建元素時(shí),可以指定多久才能從隊(duì)列中獲取當(dāng)前元素,只有延時(shí)期滿后才能從隊(duì)列中獲取元素,需要的朋友可以參考下

介紹

一個(gè)實(shí)現(xiàn)PriorityBlockingQueue實(shí)現(xiàn)延遲獲取的無界隊(duì)列,在創(chuàng)建元素時(shí),可以指定多久才能從隊(duì)列中獲取當(dāng)前元素。只有延時(shí)期滿后才能從隊(duì)列中獲取元素。

DelayQueue可以運(yùn)用在以下應(yīng)用場景:

1.緩存系統(tǒng)的設(shè)計(jì):可以用DelayQueue保存緩存元素的有效期,使用一個(gè)線程循環(huán)查詢DelayQueue,一旦能從DelayQueue中獲取元素時(shí),表示緩存有效期到了。

2.定時(shí)任務(wù)調(diào)度。使用DelayQueue保存當(dāng)天將會(huì)執(zhí)行的任務(wù)和執(zhí)行時(shí)間,一旦從DelayQueue中獲取到任務(wù)就開始執(zhí)行,從比如TimerQueue就是使用DelayQueue實(shí)現(xiàn)的。

數(shù)據(jù)結(jié)構(gòu)

public interface Delayed extends Comparable<Delayed> {
 
    /**
     * 返回與此對象相關(guān)的剩余延遲時(shí)間,以給定的時(shí)間單位表示
     */
    long getDelay(TimeUnit unit);
}

 getDelay方法一般用內(nèi)部存儲(chǔ)的事件,減去當(dāng)前事件,即為剩余延遲事件

屬性

  private final transient ReentrantLock lock = new ReentrantLock();
    private final PriorityQueue<E> q = new PriorityQueue<E>();
 
    /**
    *用于優(yōu)化內(nèi)部阻塞通知的線程
     */
    private Thread leader = null;
    private final Condition available = lock.newCondition();

以支持優(yōu)先級的PriorityQueue無界隊(duì)列作為一個(gè)容器,因?yàn)樵囟急仨殞?shí)現(xiàn)Delayed接口,可以根據(jù)元素的過期時(shí)間來對元素進(jìn)行排列,因此,先過期的元素會(huì)在隊(duì)首,每次從隊(duì)列里取出來都是最先要過期的元素。

leader是一個(gè)Thread元素,它在offer和take中都有使用,它代表當(dāng)前獲取到鎖的消費(fèi)者線程,

DelayQueue實(shí)現(xiàn)Leader-Folloer pattern

1、當(dāng)存在多個(gè)take線程時(shí),同時(shí)只生效一個(gè),即,leader線程

2、當(dāng)leader存在時(shí),其它的take線程均為follower,其等待是通過condition實(shí)現(xiàn)的

3、當(dāng)leader不存在時(shí),當(dāng)前線程即成為leader,在delay之后,將leader角色釋放還原

4、最后如果隊(duì)列還有內(nèi)容,且leader空缺,則調(diào)用一次condition的signal,喚醒掛起的take線程,其中之一將成為新的leader

5、最后在finally中釋放鎖

方法實(shí)現(xiàn)

offer,poll,peek

    public boolean offer(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            q.offer(e);
            //如果插入元素是第一個(gè)元素
            if (q.peek() == e) {
                //leader設(shè)置為null
                leader = null;
                //喚醒
                available.signal();
            }
            return true;
        } finally {
            lock.unlock();
        }
    }
    public boolean offer(E e, long timeout, TimeUnit unit) {
        return offer(e);
    }
    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();
        }
    }
   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);
                    //到期,則poll
                    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<delay,表示超時(shí)剩余時(shí)間小于到期時(shí)間,
                        nanos = available.awaitNanos(nanos);
                    else {
                        Thread thisThread = Thread.currentThread();
                        //設(shè)置當(dāng)前線程為leader
                        leader = thisThread;
                        try {
                            //等待條件
                            long timeLeft = available.awaitNanos(delay);
                            //剩余超時(shí)時(shí)間
                            nanos -= delay - timeLeft;
                        } finally {
                            if (leader == thisThread)
                                leader = null;
                        }
                    }
                }
            }
        } finally {
            if (leader == null && q.peek() != null)
                available.signal();
            lock.unlock();
        }
    }
    public E peek() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return q.peek();
        } finally {
            lock.unlock();
        }
    }

put,take

/**
     * Retrieves and removes the head of this queue, waiting if necessary
     * until an element with an expired delay is available on this queue.
     *
     * @return the head of this queue
     * @throws InterruptedException {@inheritDoc}
     */
    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        // 獲取可中斷鎖。
        lock.lockInterruptibly();
        try {
            for (;;) {
                // 從優(yōu)先級隊(duì)列中獲取隊(duì)列頭元素
                E first = q.peek();
                if (first == null)
                    // 無元素,當(dāng)前線程加入等待隊(duì)列,并阻塞
                    available.await();
                else {
                    // 通過getDelay 方法獲取延遲時(shí)間
                    long delay = first.getDelay(NANOSECONDS);
                    if (delay <= 0)
                        // 延遲時(shí)間到期,獲取并刪除頭部元素。
                        return q.poll();
                    first = null; // don't retain ref while waiting
                    if (leader != null)
                        available.await();
                    else {
                        Thread thisThread = Thread.currentThread();
                        leader = thisThread;
                        try {
                            // 線程節(jié)點(diǎn)進(jìn)入等待隊(duì)列 x 納秒。
                            available.awaitNanos(delay);
                        } finally {
                            if (leader == thisThread)
                                leader = null;
                        }
                    }
                }
            }
        } finally {
            // leader == null且還存在元素的話,喚醒一個(gè)消費(fèi)線程。
            if (leader == null && q.peek() != null)
                available.signal();
            lock.unlock();
        }
    }
   public void put(E e) {
        offer(e);
    }

take()方法邏輯:

1.獲取鎖

2.取出優(yōu)先級隊(duì)列q的首元素

3.如果元素q的隊(duì)首/隊(duì)列為空,阻塞

4.如果元素q的隊(duì)首(first)不為空,獲得這個(gè)元素的delay時(shí)間值,如果first的延遲delay時(shí)間值為0的話,說明該元素已經(jīng)到了可以使用的時(shí)間,調(diào)用poll方法彈出該元素,跳出方法

5.如果first的延遲delay時(shí)間值不為0的話,釋放元素first的引用,避免內(nèi)存泄露

6.循環(huán)以上操作,直到return

leader作用

如果leader不為null,說明已經(jīng)有消費(fèi)者線程拿到鎖,直接阻塞當(dāng)前線程,如果leader為null,把當(dāng)前線程賦值給leader,并等待剩余的到期時(shí)間,最后釋放leader,這里我們想象著我們有個(gè)多個(gè)消費(fèi)者線程用take方法去取,如果沒有l(wèi)eader!=null的判斷,這些線程都會(huì)無限循環(huán),直到返回第一個(gè)元素,很顯然很浪費(fèi)資源。所以leader的作用是設(shè)置一個(gè)標(biāo)記,來避免消費(fèi)者的無腦競爭。

到此這篇關(guān)于Java中的DelayQueue源碼解析的文章就介紹到這了,更多相關(guān)DelayQueue源碼解析內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring boot實(shí)現(xiàn)數(shù)據(jù)庫讀寫分離的方法

    Spring boot實(shí)現(xiàn)數(shù)據(jù)庫讀寫分離的方法

    本篇文章主要介紹了Spring boot實(shí)現(xiàn)數(shù)據(jù)庫讀寫分離的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-01-01
  • Springboot如何根據(jù)實(shí)體類生成數(shù)據(jù)庫表

    Springboot如何根據(jù)實(shí)體類生成數(shù)據(jù)庫表

    這篇文章主要介紹了Springboot如何根據(jù)實(shí)體類生成數(shù)據(jù)庫表的操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java文件處理之使用itextpdf實(shí)現(xiàn)excel轉(zhuǎn)pdf

    Java文件處理之使用itextpdf實(shí)現(xiàn)excel轉(zhuǎn)pdf

    在文件處理中,經(jīng)常有文件類型轉(zhuǎn)換的使用場景,本文主要介紹了如何使用poi以及itextpdf完成excel轉(zhuǎn)pdf的操作,需要的小伙伴可以參考一下
    2024-02-02
  • Java正確使用訪問修飾符的姿勢

    Java正確使用訪問修飾符的姿勢

    訪問修飾符是Java語法中很基礎(chǔ)的一部分,但是能正確的使用Java訪問修飾符的程序員只在少數(shù),下面這篇文章主要給大家介紹了關(guān)于Java正確使用訪問修飾符的姿勢,需要的朋友可以參考下
    2021-11-11
  • Mybatis的插件運(yùn)行原理及如何編寫一個(gè)插件

    Mybatis的插件運(yùn)行原理及如何編寫一個(gè)插件

    這篇文章主要介紹了Mybatis的插件運(yùn)行原理及如何編寫一個(gè)插件 ,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-07-07
  • SpringCloud微服務(wù)中跨域配置的方法詳解

    SpringCloud微服務(wù)中跨域配置的方法詳解

    在使用SpringCloud實(shí)現(xiàn)微服務(wù)時(shí),經(jīng)常會(huì)碰到前端頁面訪問多個(gè)二級域名的情況,跨域是首先要解決的問題。解決這個(gè)問題,可以從兩方面入手,一種方案是在微服務(wù)各自的業(yè)務(wù)模塊中實(shí)現(xiàn),即在SpringBoot層實(shí)現(xiàn),另外一種方案就是在Gateway層實(shí)現(xiàn)
    2023-02-02
  • Java中Boolean與字符串或者數(shù)字1和0的轉(zhuǎn)換實(shí)例

    Java中Boolean與字符串或者數(shù)字1和0的轉(zhuǎn)換實(shí)例

    下面小編就為大家?guī)硪黄狫ava中Boolean與字符串或者數(shù)字1和0的轉(zhuǎn)換實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-07-07
  • java多線程編程之從線程返回?cái)?shù)據(jù)的兩種方法

    java多線程編程之從線程返回?cái)?shù)據(jù)的兩種方法

    從線程中返回?cái)?shù)據(jù)和向線程傳遞數(shù)據(jù)類似。也可以通過類成員以及回調(diào)函數(shù)來返回?cái)?shù)據(jù)。但類成員在返回?cái)?shù)據(jù)和傳遞數(shù)據(jù)時(shí)有一些區(qū)別,下面讓我們來看看它們區(qū)別在哪
    2014-01-01
  • JDBC 實(shí)現(xiàn)通用的增刪改查基礎(chǔ)類方法

    JDBC 實(shí)現(xiàn)通用的增刪改查基礎(chǔ)類方法

    下面小編就為大家分享一篇JDBC 實(shí)現(xiàn)通用的增刪改查基礎(chǔ)類方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-01-01
  • Java聊天室之使用Socket實(shí)現(xiàn)傳遞對象

    Java聊天室之使用Socket實(shí)現(xiàn)傳遞對象

    這篇文章主要為大家詳細(xì)介紹了Java簡易聊天室之使用Socket實(shí)現(xiàn)傳遞對象功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以了解一下
    2022-10-10

最新評論

探索| 汉川市| 湖北省| 蓝田县| 禄丰县| 无锡市| 南阳市| 阿拉善右旗| 东阿县| 应用必备| 合肥市| 台江县| 靖远县| 利辛县| 青河县| 文化| 溆浦县| 彭泽县| 焦作市| 贞丰县| 株洲县| 金寨县| 丰原市| 土默特左旗| 东辽县| 临夏县| 自贡市| 伊春市| 柞水县| 新蔡县| 余江县| 合江县| 承德市| 丹江口市| 公主岭市| 报价| 邹城市| 泰州市| 宜宾县| 高邑县| 寿宁县|