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

Java多線程之等待隊(duì)列DelayQueue詳解

 更新時(shí)間:2023年12月14日 11:03:15   作者:愛喝咖啡的程序員  
這篇文章主要介紹了Java多線程之等待隊(duì)列DelayQueue詳解,    DelayQueue被稱作"等待隊(duì)列"或"JDK延遲隊(duì)列",存放著實(shí)現(xiàn)了Delayed接口的對(duì)象,對(duì)象需要設(shè)置到期時(shí)間,當(dāng)且僅當(dāng)對(duì)象到期,才能夠從隊(duì)列中被取走(并非一定被取走),需要的朋友可以參考下

一. 概念

DelayQueue被稱作"等待隊(duì)列"或"JDK延遲隊(duì)列",存放著實(shí)現(xiàn)了Delayed接口的對(duì)象。對(duì)象需要設(shè)置到期時(shí)間,當(dāng)且僅當(dāng)對(duì)象到期,才能夠從隊(duì)列中被取走(并非一定被取走)。DelayQueue的內(nèi)部使用了PriorityQueue來存放元素,需要元素實(shí)現(xiàn)Comparable接口,優(yōu)先級(jí)隊(duì)列會(huì)根據(jù)對(duì)象的到期時(shí)間實(shí)現(xiàn)有序排序。

二. 案例

本案例參考了《Java編程思想》第21章P726頁的例子。

1. 定義延遲任務(wù)對(duì)象

class DelayedTask implements Runnable, Delayed { // Delayed接口必須實(shí)現(xiàn),Runnable接口可以不實(shí)現(xiàn)
    private static int counter = 0;
    private final int id = counter++;
    /**
     * 延遲的時(shí)間(單位: 毫秒)
     */
    private final int delta;
    /**
     * 任務(wù)準(zhǔn)備執(zhí)行的時(shí)間點(diǎn)(單位: 納秒)
     */
    private final long trigger;
    protected static List<DelayedTask> sequence = new ArrayList<>();
    public DelayedTask(int delayInMilliseconds) {
        delta = delayInMilliseconds;
        trigger = System.nanoTime() + NANOSECONDS.convert(delta, MILLISECONDS);
        sequence.add(this);
    }
    @Override
    public long getDelay(@NotNull TimeUnit unit) {
        // 過期時(shí)間
        return unit.convert(trigger - System.nanoTime(), NANOSECONDS);
    }
    /**
     * 用于在過期任務(wù)隊(duì)列中,任務(wù)之間執(zhí)行順序的排序
     */
    @Override
    public int compareTo(@NotNull Delayed arg) {
        DelayedTask that = (DelayedTask)arg;
        if(trigger < that.trigger) return -1;
        if(trigger > that.trigger) return 1;
        return 0;
    }
    @Override
    public void run() {
        System.out.println(this + " ");
    }
    @Override
    public String toString() {
        // 語法規(guī)則: %[argument_index$][flags][width][.precision]conversion
        // %后面的1$指的是第一個(gè)參數(shù),也就是delta
        // $后面的-4d指的是如果數(shù)據(jù)總長(zhǎng)度不夠4位,則由右向左補(bǔ)足空格
        return String.format("[%1$-4d]", delta) + " Task " + id;
    }
    public String summary() {
        return "(" + id + ":" + delta + ")";
    }
    public static class EndSentinel extends DelayedTask {
        private ExecutorService exec;
        public EndSentinel(int delay, ExecutorService e) {
            super(delay);
            exec = e;
        }
        @Override
        public void run() {
            for(DelayedTask pt : sequence) {
                System.out.println(pt.summary() + " ");
            }
            System.out.println();
            System.out.println(this + " Calling shutdownNow()");
            exec.shutdownNow();
        }
    }
}

2. 定義隊(duì)列的消費(fèi)者

class DelayedTaskConsumer implements Runnable {
    private DelayQueue<DelayedTask> q;
    public DelayedTaskConsumer(DelayQueue<DelayedTask> q) {
        this.q = q;
    }
    @Override
    public void run() {
        try {
            while(!Thread.interrupted()) {
                // DelayQueue take()
                // 取出隊(duì)列中的head元素,若隊(duì)列中沒有任何延遲到期的元素存在,則該方法將會(huì)被阻塞
                // 此時(shí)有兩種可能: 1. 隊(duì)列中沒有元素 2. 隊(duì)列中有元素,但都尚未過期
                // 直到隊(duì)列中有延遲到期的元素為止
                // 即便是不讓DelayedTask實(shí)現(xiàn)Runnable接口,本例的執(zhí)行結(jié)果也不會(huì)發(fā)生改變。
                // 因?yàn)榇颂幹苯诱{(diào)用了run()方法,并沒有分配其他線程去驅(qū)動(dòng)DelayedTask
                q.take().run();
            }
        } catch (InterruptedException e) {
            // Acceptable way to exit
            System.out.println("Acceptable way to exit");
        }
        System.out.println("Finished DelayedTaskConsumer");
    }
}

3. main方法

public class DelayQueueDemo {
    public static void main(String[] args) {
        test2();
    }
    public static void test1() {
        Random random = new Random(47);
        ExecutorService exec = Executors.newCachedThreadPool();
        DelayQueue<DelayedTask> queue = new DelayQueue<>();
        // Fill with tasks that have random delays:
        for(int i = 0; i < 5; i++) {
            queue.put(new DelayedTask(random.nextInt(5000)));
        }
        //使用DelayQueue take()的方式獲取任務(wù)
        queue.add(new DelayedTask.EndSentinel(5000, exec));
        exec.execute(new DelayedTaskConsumer(queue));
    }
    public static void test2() {
        Random random = new Random(47);
        ExecutorService exec = Executors.newCachedThreadPool();
        DelayQueue<DelayedTask> queue = new DelayQueue<>();
        // Fill with tasks that have random delays:
        for(int i = 0; i < 5; i++) {
            queue.put(new DelayedTask(random.nextInt(5000)));
        }
        //使用DelayQueue poll()方式獲取任務(wù)
        while(queue.size() != 0) {
            // 每執(zhí)行一次DelayQueue poll()且返回的元素不是null,則DelayQueue等待隊(duì)列的元素個(gè)數(shù)會(huì)減一
            DelayedTask task = queue.poll();
            if(task != null) {
                System.out.println(LocalDateTime.now(ZoneId.of("+08:00")));
            }
        }
    }
}

由于案例中給Random設(shè)置了種子,因此過期時(shí)間的值是可以預(yù)測(cè)的(每次執(zhí)行都保持一致)。test1()的執(zhí)行結(jié)果如下:

 * [555 ] Task 1
 * [961 ] Task 4
 * [1693] Task 2
 * [1861] Task 3
 * [4258] Task 0
 * (0:4258)
 * (1:555)
 * (2:1693)
 * (3:1861)
 * (4:961)
 * (5:5000)

其中,[]方括號(hào)代表任務(wù)的執(zhí)行順序,()代表任務(wù)的創(chuàng)建順序。顯而易見,任務(wù)的創(chuàng)建順序與執(zhí)行順序沒有任何關(guān)系,任務(wù)嚴(yán)格按照延遲時(shí)間的長(zhǎng)短運(yùn)行。

三. 總結(jié)

1. 延遲隊(duì)列中的對(duì)象只有到期后才能夠從隊(duì)列中被取走。(若沒有到期或隊(duì)頭元素為null,則DelayQueue會(huì)陷入阻塞,說白了就是循環(huán)等待,可以參考DelayQueue的take()方法,寫了一個(gè)for(;;) )

2. 對(duì)象并非到期后就會(huì)被立刻取走,每次取出(poll())的僅僅是到期元素中隊(duì)頭元素。

3. 任務(wù)的創(chuàng)建順序與任務(wù)的執(zhí)行順序沒有任何關(guān)系,延遲隊(duì)列中任務(wù)的排序順序與過期任務(wù)對(duì)Comparable接口compareTo()方法的具體實(shí)現(xiàn)有關(guān)。

四. 疑問

還是以下圖為例

若在插入c之前,時(shí)間過去了100納秒,c仍然應(yīng)該排列在b之前嗎?照此推論,只要把過期時(shí)長(zhǎng)控制在500納秒以內(nèi),所有插入的任務(wù)都應(yīng)該在b之前執(zhí)行(因?yàn)檫^期時(shí)長(zhǎng)比b短),這是不是非常不合理?既然時(shí)間過去了100納秒,為什么不將a的過期時(shí)長(zhǎng)改變成900納秒,b的過期時(shí)長(zhǎng)改變成400納秒,最后讓b在c之前執(zhí)行呢?

遺憾的是,在DelayQueue的源碼中,并沒有看到對(duì)容器PriorityQueue內(nèi)部元素有做任何定時(shí)器,試圖改變?nèi)蝿?wù)過期時(shí)長(zhǎng)的代碼。

到此這篇關(guān)于Java多線程之等待隊(duì)列DelayQueue詳解的文章就介紹到這了,更多相關(guān)Java的等待隊(duì)列DelayQueue內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java迭代器與Collection接口超詳細(xì)講解

    Java迭代器與Collection接口超詳細(xì)講解

    Collection也稱集合,集合概述:集合是Java中提供的一種容器,可以用來存儲(chǔ)多個(gè)數(shù)據(jù)。Iterator(迭代器)不是一個(gè)集合,它是一種用于訪問集合的方法,可用于迭代 ArrayList 和 HashSet 等集合
    2022-07-07
  • JAVA讀取文本文件內(nèi)容實(shí)例代碼

    JAVA讀取文本文件內(nèi)容實(shí)例代碼

    這篇文章主要給大家介紹了關(guān)于JAVA讀取文本文件內(nèi)容的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Java基于API接口爬取商品數(shù)據(jù)的示例代碼

    Java基于API接口爬取商品數(shù)據(jù)的示例代碼

    Java作為一種流行的編程語言,可以用于編寫程序來調(diào)用這些API接口,從而獲取商品數(shù)據(jù),本文將介紹如何使用Java基于API接口爬取商品數(shù)據(jù),包括請(qǐng)求API、解析JSON數(shù)據(jù)、存儲(chǔ)數(shù)據(jù)等步驟,并提供相應(yīng)的代碼示例,感興趣的朋友跟隨小編一起看看吧
    2023-10-10
  • Java微信授權(quán)登錄小程序接口流程

    Java微信授權(quán)登錄小程序接口流程

    微信授權(quán)登錄小程序的流程是一個(gè)涉及前端和后端交互的過程,主要目的是讓用戶能夠使用微信賬號(hào)快速登錄小程序,避免重復(fù)輸入用戶名和密碼,下面給大家介紹Java微信授權(quán)登錄小程序接口流程,感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • java虛擬機(jī)jvm方法區(qū)實(shí)例講解

    java虛擬機(jī)jvm方法區(qū)實(shí)例講解

    在本篇文章里小編給大家整理的是一篇關(guān)于java虛擬機(jī)jvm方法區(qū)實(shí)例講解內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。
    2021-02-02
  • 詳解MyBatis多數(shù)據(jù)源配置(讀寫分離)

    詳解MyBatis多數(shù)據(jù)源配置(讀寫分離)

    這篇文章主要介紹了詳解MyBatis多數(shù)據(jù)源配置(讀寫分離),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-01-01
  • 詳解SpringBoot讀取Yml配置文件的3種方法

    詳解SpringBoot讀取Yml配置文件的3種方法

    本文主要介紹了詳解SpringBoot讀取Yml配置文件的3種方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • mybatisPlus實(shí)現(xiàn)邏輯刪除,自動(dòng)生成創(chuàng)建時(shí)間和更新時(shí)間方式

    mybatisPlus實(shí)現(xiàn)邏輯刪除,自動(dòng)生成創(chuàng)建時(shí)間和更新時(shí)間方式

    MyBatisPlus框架中,通過@TableField(fill=FieldFill.INSERT)和@TableField(fill=FieldFill.UPDATE)注解可以實(shí)現(xiàn)在插入和更新時(shí)自動(dòng)填充字段,比如創(chuàng)建時(shí)間和更新時(shí)間,使用@TableLogic注解標(biāo)識(shí)邏輯刪除字段
    2024-09-09
  • Java向上轉(zhuǎn)型與向下轉(zhuǎn)型超詳細(xì)圖解

    Java向上轉(zhuǎn)型與向下轉(zhuǎn)型超詳細(xì)圖解

    我們?cè)贘ava編程中經(jīng)常碰到類型轉(zhuǎn)換,對(duì)象類型轉(zhuǎn)換主要包括向上轉(zhuǎn)型和向下轉(zhuǎn)型,這篇文章主要介紹了Java向上轉(zhuǎn)型與向下轉(zhuǎn)型的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-04-04
  • java request.getHeader(

    java request.getHeader("user-agent")獲取瀏覽器信息的方法

    這篇文章主要介紹了java request.getHeader("user-agent")獲取瀏覽器信息的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03

最新評(píng)論

桐乡市| 开远市| 灵宝市| 蛟河市| 彭山县| 兴义市| 刚察县| 长春市| 凤凰县| 龙山县| 当阳市| 张家界市| 苍梧县| 澜沧| 兰西县| 阳江市| 密山市| 张北县| 红河县| 靖安县| 寿阳县| 横山县| 卢氏县| 霍林郭勒市| 永春县| 栖霞市| 三河市| 宁南县| 普兰店市| 苗栗县| 正镶白旗| 新和县| 内江市| 军事| 老河口市| 台南市| 榆中县| 常州市| 桂林市| 津南区| 商都县|