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

Java簡單實(shí)現(xiàn)定時器

 更新時間:2021年04月26日 10:48:48   作者:GlorygloryGlory  
這篇文章主要為大家詳細(xì)介紹了Java簡單實(shí)現(xiàn)定時器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了Java簡單實(shí)現(xiàn)定時器的具體代碼,供大家參考,具體內(nèi)容如下

一、定時器

定時器相當(dāng)于一個任務(wù)管理器。有些任務(wù)可能現(xiàn)在執(zhí)行, 有些任務(wù)可能過1個小時,甚至很久才會執(zhí)行。定時器就是對這些任務(wù)進(jìn)行管理監(jiān)視, 如果一個任務(wù)執(zhí)行時間到了,定時器就會將這個任務(wù)執(zhí)行。 保證所有的任務(wù)都會在合適的時間執(zhí)行。

二、定時器的實(shí)現(xiàn)

對于定時器的實(shí)現(xiàn),我們可以劃分為3個部分。

1、 使用一個Task類描述每一個任務(wù)(里面包含任務(wù)的執(zhí)行方法, 定時時間)。
2、 使用優(yōu)先級隊(duì)列管理這些任務(wù)類。

2.1 我們都知道優(yōu)先級隊(duì)列底層實(shí)現(xiàn)是堆(以小根堆為例), 堆頂?shù)脑厥撬械脑氐淖钚≈怠?我們以任務(wù)的定時時間為比較原則構(gòu)建, 這樣就可以保證堆頂元素的任務(wù)執(zhí)行時間是最短的(這樣的實(shí)現(xiàn),我們需要在Task類內(nèi)部定義比較規(guī)則-即重寫Comparable接口的CompareTo方法)。

2.2 當(dāng)一個任務(wù)執(zhí)行完畢, 就會從優(yōu)先級隊(duì)列取出poll掉, 然后內(nèi)部重新組織保證新的堆頂元素是定時時間最短的。

2.3 如果說堆頂?shù)娜蝿?wù)定時時間還沒有到達(dá)(當(dāng)然后續(xù)的任務(wù)定時時間肯定會更長,不會被執(zhí)行)

3、使用一個線程循環(huán)掃描優(yōu)先級隊(duì)列, 相當(dāng)于一個監(jiān)控線程,循環(huán)判斷堆頂任務(wù)是否滿足執(zhí)行時間。

三、定時器的組成

1、制定任務(wù)類Task

Task類包含任務(wù)的 執(zhí)行方法 和 定時時間。

1.1 執(zhí)行方法我采用封裝Runnable中run方法實(shí)現(xiàn), 這樣做是為了后續(xù)添加任務(wù)時方便寫執(zhí)行邏輯。
1.2 定時時間就是long類型的變量
1.3 制定比較規(guī)則, 后續(xù)優(yōu)先級隊(duì)列中存放的是Task對象(而在內(nèi)部構(gòu)建時,需要比較兩個Task對象的),對于對象的比較, 我們以對象的定時時間為規(guī)則, 制定小根堆。

static class Task implements Comparable<Task>{
        //Runnable類中有一個run方法, 通過這個方法實(shí)現(xiàn)任務(wù)的執(zhí)行
        private Runnable command;
        //time表示執(zhí)行的時間
        private long time;

        //構(gòu)造方法
        public Task(Runnable command, long time) {
            this.command = command;
            this.time = System.currentTimeMillis() + time;  //將時間轉(zhuǎn)化為絕對時間
        }

        //執(zhí)行任務(wù)的邏輯
        public void run() {
            command.run();
        }

        //定義比較方法 - 方便后續(xù)的優(yōu)先級隊(duì)列構(gòu)建

        @Override
        public int compareTo(Task o) {
            return (int)(this.time - o.time);
        }
    }

2、監(jiān)管線程&定時器對象Timer

監(jiān)管線程Worker中包含優(yōu)先級隊(duì)列(小根堆)queue 和 循環(huán)監(jiān)管的流程。

Timer對象封裝了監(jiān)管線程Woker 和 任務(wù)的添加方法schedule()

關(guān)于監(jiān)管線程的優(yōu)化

2.1 循環(huán)監(jiān)控存在一個弊端,那就是一直循環(huán)判斷, 占用CPU資源。
(假如堆首任務(wù)的執(zhí)行是1小時后, 再次期間監(jiān)管線程會跑1小時循環(huán)判斷。) 

解決方法: 可以通過線程阻塞和喚醒來解決。在下面代碼有詳細(xì)注釋和實(shí)現(xiàn)。

2.1.1 如果任務(wù)1小時后執(zhí)行, 我們讓監(jiān)管線程wait(1小時), 但在此期間如果有新的任務(wù)添加進(jìn)來(可能新的任務(wù)需要等30分鐘就可以執(zhí)行,堆首元素發(fā)生變化) ,這時需要喚醒監(jiān)管線程來重新判斷。(由于wait和notify方法不在用一個類中實(shí)現(xiàn), 我們通過一個Object(mailBox)來阻塞、喚醒)

//檢測線程, 繼承Thread類,重寫內(nèi)部run方法,屬于線程的創(chuàng)建方法之一。
    static class Worker extends Thread {
     //優(yōu)先級隊(duì)列 - JUC包里面
        private PriorityBlockingQueue<Task> queue = null;
        //為了對監(jiān)管線程進(jìn)行阻塞和喚醒,采用同一對象
        private Object mailBox = null;
  
  //構(gòu)造函數(shù)
        public Worker(PriorityBlockingQueue<Task> queue, Object mailBox) {
            this.queue = queue;
            this.mailBox = mailBox;
        }

        @Override
        public void run() {
            //實(shí)現(xiàn)具體的執(zhí)行邏輯
            while(true) {
                try {
                    //1、取優(yōu)先級隊(duì)列的隊(duì)首元素
                    Task task = queue.peek();
                    //2、比較隊(duì)首的元素的時間是否大于當(dāng)前時間
                    if(task == null) {
                        continue;
                    }
                    long curTime = System.currentTimeMillis();
                    if(task.time > curTime) {
                        //時間還沒有到, 由于取出了任務(wù), 需要重新放置回去
                        //優(yōu)化1: 空循環(huán)等待 - wait(time) 讓線程休眠time時間,然后在執(zhí)行
                        //       如果在等待期間有新的任務(wù)添加, 這個時候我們喚醒線程, 繼續(xù)判斷(因?yàn)榇嬖谛碌臅r間過短需要立即執(zhí)行)
                        //       這個只需要添加一個新任務(wù)時, 喚醒即可
                        //優(yōu)化2: 訪問隊(duì)首元素而不是取出, 防止無所謂的刪除、插入。(維護(hù)優(yōu)先級隊(duì)列是有消耗的)
                        long gapTime = task.time - curTime;
                        synchronized (mailBox) {
                            mailBox.wait(gapTime);
                        }
                    }
                    else {
                        //直接執(zhí)行
                        //如果執(zhí)行到了, 則會刪除頭部元素, 調(diào)用任務(wù)的執(zhí)行過程。
                        task = queue.take();
                        task.run();
                    }
                }
                catch(InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
            }
        }
    }

    //定時器簡單實(shí)現(xiàn)
    static class Timer {
        //定時器的實(shí)現(xiàn)步驟
        //1、用一個類描述任務(wù)
        //2、用優(yōu)先級隊(duì)列管理這些任務(wù), 比較方法通過任務(wù)的制定時間,每次取隊(duì)首元素
        //   隊(duì)首元素是執(zhí)行時間最近的
        private PriorityBlockingQueue<Task> queue = new PriorityBlockingQueue<>();
        //3、用一個線程來循環(huán)掃描當(dāng)前的阻塞隊(duì)列,判斷隊(duì)首的執(zhí)行時間, 如果執(zhí)行時間到了,那就執(zhí)行。

        //4、創(chuàng)建一個Object對象,用于設(shè)置線程阻塞使用的, 存在線程阻塞, 添加任務(wù)時喚醒的操作
        private Object mailBox = new Object();

        //構(gòu)造函數(shù)
        public Timer() {
            //創(chuàng)建線程
            Worker worker = new Worker(queue, mailBox);
            worker.start();
        }


        //4、提供一個方法, 讓調(diào)用者能夠把任務(wù)安排起來
        public void schedule(Runnable command, long time) {
            Task task = new Task(command, time);
            queue.put(task);
            synchronized (mailBox) {
                mailBox.notify();
            }
        }
    }

3、測試代碼

其中添加了4個任務(wù), 分別是2s、5s、7s、10s后執(zhí)行。

public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("郝夢武一號任務(wù)執(zhí)行, 執(zhí)行代號:閃電;  定時時間:2s");
            }
        }, 2000);

        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("郝夢武二號任務(wù)執(zhí)行, 執(zhí)行代號:暴風(fēng);  定時時間:5s");
            }
        }, 5000);

        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("郝夢武三號任務(wù)執(zhí)行, 執(zhí)行代號:狂風(fēng);  定時時間:7s");
            }
        }, 7000);

        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("郝夢武三號任務(wù)執(zhí)行, 執(zhí)行代號:地震;  定時時間:10s");
            }
        }, 10000);
    }

4、測試結(jié)果

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解java裝飾模式(Decorator Pattern)

    詳解java裝飾模式(Decorator Pattern)

    這篇文章主要為大家詳細(xì)介紹了java裝飾模式Decorator Pattern,這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它是作為現(xiàn)有的類的一個包裝,對裝飾器模式感興趣的小伙伴們可以參考一下
    2016-04-04
  • Mybatis動態(tài)SQL foreach標(biāo)簽用法實(shí)例

    Mybatis動態(tài)SQL foreach標(biāo)簽用法實(shí)例

    這篇文章主要介紹了Mybatis動態(tài)SQL foreach標(biāo)簽用法實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-10-10
  • 使用Java自制一個一個Nacos

    使用Java自制一個一個Nacos

    Nacos是?Dynamic?Naming?and?Configuration?Service的首字母簡稱,一個更易于構(gòu)建云原生應(yīng)用的動態(tài)服務(wù)發(fā)現(xiàn)、配置管理和服務(wù)管理平臺,本文將嘗試用Java實(shí)現(xiàn)一個Nacos,感興趣的可以了解下
    2024-01-01
  • Windows系統(tǒng)下Eclipse搭建ESP32編譯環(huán)境及安裝過程

    Windows系統(tǒng)下Eclipse搭建ESP32編譯環(huán)境及安裝過程

    Ecppse 使用了 ESP-IDF 中的 Makefile 支持。這意味著您需要從創(chuàng)建 ESP-IDF 項(xiàng)目開始。您可以使用 github 中的 idf-template 項(xiàng)目,接下來通過本文給大家介紹Windows系統(tǒng)下Eclipse搭建ESP32編譯環(huán)境及安裝過程,感興趣的朋友一起看看吧
    2021-10-10
  • SpringBoot應(yīng)用War包形式部署到外部Tomcat的方法

    SpringBoot應(yīng)用War包形式部署到外部Tomcat的方法

    這篇文章主要介紹了SpringBoot應(yīng)用War包形式部署到外部Tomcat的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08
  • Spring中的@Autowired、@Qualifier和@Primary注解詳解

    Spring中的@Autowired、@Qualifier和@Primary注解詳解

    這篇文章主要介紹了Spring中的@Autowired、@Qualifier和@Primary注解詳解,@Autowired?注解,可以對類成員變量、方法和構(gòu)造函數(shù)進(jìn)行標(biāo)注,完成自動裝配的工作,@Autowired?是默認(rèn)根據(jù)?byType?進(jìn)行自動裝配的,需要的朋友可以參考下
    2023-11-11
  • 教你如何區(qū)分Spring與Structs2中間件

    教你如何區(qū)分Spring與Structs2中間件

    這篇文章主要介紹了教你如何區(qū)分Spring與Structs2中間件,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-03-03
  • Mybatis詳解在注解sql時報錯的解決方法

    Mybatis詳解在注解sql時報錯的解決方法

    MyBatis-Plus 是一個 Mybatis 增強(qiáng)版工具,在 MyBatis 上擴(kuò)充了其他功能沒有改變其基本功能,為了簡化開發(fā)提交效率而存在,本篇文章帶你看看在注解sql時所報出的錯誤解決
    2022-03-03
  • java根據(jù)url抓取并生成縮略圖的示例

    java根據(jù)url抓取并生成縮略圖的示例

    這篇文章主要介紹了java根據(jù)url抓取并生成縮略圖的示例,需要的朋友可以參考下
    2014-05-05
  • Java 數(shù)據(jù)結(jié)構(gòu)與算法系列精講之二叉堆

    Java 數(shù)據(jù)結(jié)構(gòu)與算法系列精講之二叉堆

    二叉堆是一種特殊的堆,其實(shí)質(zhì)是完全二叉樹。二叉堆有兩種:最大堆和最小堆。最大堆是指父節(jié)點(diǎn)鍵值總是大于或等于任何一個子節(jié)點(diǎn)的鍵值。而最小堆恰恰相反,指的是父節(jié)點(diǎn)鍵值總是小于任何一個子節(jié)點(diǎn)的鍵值
    2022-02-02

最新評論