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

Java中定時器java.util.Timer的簡單模擬

 更新時間:2023年07月18日 11:57:05   作者:會飛的喵喵  
在Java中,定時器(Timer)是一個工具類,用于安排任務(wù)在指定時間后執(zhí)行或以指定的時間間隔重復(fù)執(zhí)行,本文就來講講如何簡單模擬實(shí)現(xiàn)定時器吧

1.定時器

1.1 含義

在Java中,定時器(Timer)是一個工具類,用于安排任務(wù)(Task)在指定時間后執(zhí)行或以指定的時間間隔重復(fù)執(zhí)行。它可以用于執(zhí)行定時任務(wù)、定時調(diào)度和時間延遲等操作。

定時器(Timer)可以應(yīng)用于許多場景,比如:

  • 調(diào)度任務(wù):當(dāng)你需要按照預(yù)定時間執(zhí)行任務(wù)時,可以使用定時器。例如,每天凌晨執(zhí)行數(shù)據(jù)備份、定時生成報(bào)表、定時發(fā)送通知等。
  • 超時處理:當(dāng)你需要處理某個操作的超時情況時,可以使用定時器。例如,設(shè)置一個操作的超時時間,如果在規(guī)定時間內(nèi)未完成,則執(zhí)行相應(yīng)的超時處理邏輯。

1.2 標(biāo)準(zhǔn)庫中的定時器

Java中的定時器:java.util.Timer,它的常用方法:

方法描述
schedule(TimerTask task, Date time)安排在指定時間執(zhí)行任務(wù)
schedule(TimerTask task, long delay)安排在指定延遲時間后執(zhí)行任務(wù)
schedule(TimerTask task, long delay, long period)安排在指定延遲時間后以指定的時間間隔重復(fù)執(zhí)行任務(wù)
scheduleAtFixedRate(TimerTask task, Date firstTime, long period)安排在指定時間開始以固定的時間間隔重復(fù)執(zhí)行任務(wù)
scheduleAtFixedRate(TimerTask task, long delay, long period)安排在指定延遲時間后以固定的時間間隔重復(fù)執(zhí)行任務(wù)
cancel()取消定時器的所有任務(wù)
purge()從定時器的任務(wù)隊(duì)列中刪除所有已取消的任務(wù)
public class Main {
    public static void main(String[] args) {
        Timer timer = new Timer();
        //調(diào)度指定的任務(wù)在指定的延遲時間(3000ms)后執(zhí)行。
        timer.schedule(new TimerTask() {
            //待執(zhí)行的任務(wù)
            @Override
            public void run() {
                System.out.println("hello");
            }
        },3000);
    }
}

也可以一次注冊多個任務(wù):

public class Main {
    public static void main(String[] args) {
        Timer timer = new Timer();
        //在指定的延遲時間(1000ms)后執(zhí)行。
        timer.schedule(new TimerTask() {
            //待執(zhí)行的任務(wù)
            @Override
            public void run() {
                System.out.println("任務(wù)1");
            }
        },1000);
        //在指定的延遲時間(2000ms)后執(zhí)行。
        timer.schedule(new TimerTask() {
            //待執(zhí)行的任務(wù)
            @Override
            public void run() {
                System.out.println("任務(wù)2");
            }
        },2000);
        //在指定的延遲時間(3000ms)后執(zhí)行。
        timer.schedule(new TimerTask() {
            //待執(zhí)行的任務(wù)
            @Override
            public void run() {
                System.out.println("任務(wù)3");
            }
        },3000);
    }
}

2.簡單模擬實(shí)現(xiàn)定時器

2.1 實(shí)現(xiàn)思路

1.使用一個數(shù)據(jù)結(jié)構(gòu)來保存所有的任務(wù),這些任務(wù)是根據(jù)時間的大小來進(jìn)行先后執(zhí)行的,所以這里使用優(yōu)先級隊(duì)列。由于這里是多線程的環(huán)境,所以這里采用PriorityBlockingQueue(優(yōu)先級阻塞隊(duì)列),時間越小優(yōu)先級越高。

2.我們需要使用一個線程來掃描定時器里面的任務(wù)是否到達(dá)執(zhí)行時間,由于我們采用的是優(yōu)先級隊(duì)列數(shù)據(jù)結(jié)構(gòu),所以只需掃描隊(duì)首元素。如果隊(duì)首還沒到執(zhí)行時間,那么后面的元素不可能到達(dá)執(zhí)行時間。

3.任務(wù)用一個類MyTask來表示,這里需要實(shí)現(xiàn)Comparable接口,因?yàn)樗枰嫒雰?yōu)先級隊(duì)列。其中的屬性:

//表示定時器中的任務(wù)
class MyTask implements Comparable<MyTask>{
    //要執(zhí)行的任務(wù)內(nèi)容
    private Runnable runnable;
    //延遲時間
    private long time;
    public MyTask(Runnable runnable, long time) {
        this.runnable = runnable;
        this.time = time;
    }
    //為了便于后面的比較,需要提供 get 方法
    public long getTime() {
        return time;
    }
    //表示任務(wù)開始執(zhí)行
    public void run(){
        this.runnable.run();
    }
    @Override
    public int compareTo(MyTask o) {
        return (int)(this.getTime() - o.getTime());
    }
}

4.實(shí)現(xiàn)添加任務(wù)的方法schedule

public class MyTimer {
    //掃描線程
    private Thread thread;
    //優(yōu)先級隊(duì)列(這里為阻塞隊(duì)列)
    private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();
    /**
     * 這個方法是用來注冊(添加)任務(wù)的
     * @param runnable 表示待執(zhí)行的任務(wù)
     * @param after 表示多少時間過后執(zhí)行任務(wù)
     */
    public void schedule(Runnable runnable,long after){
        //添加任務(wù),注意這里的時間是 System.currentTimeMillis() + after
        MyTask task = new MyTask(runnable,System.currentTimeMillis() + after);
        queue.put(task);
    }
}

5.添加一個線程來檢測隊(duì)首元素:

    //當(dāng)創(chuàng)建對象的時候就直接開啟一個線程
	public MyTimer(){
        thread = new Thread(()->{
           while(true){
               //取出隊(duì)首,如果到時間了就執(zhí)行。
               try {
                   MyTask myTask = queue.take();
                   long curTime = System.currentTimeMillis();
                   if(curTime < myTask.getTime()){
                       //時間未到,不執(zhí)行
                       queue.put(myTask);
                   }else {
                       //時間已到,執(zhí)行
                       myTask.run();
                   }
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        });
        thread.start();
    }

就這樣就完了嗎?其實(shí)不然,在上面代碼中while (true)轉(zhuǎn)的太快了, 造成了無意義的 CPU 浪費(fèi),如果第一個任務(wù)設(shè)定的是 1 min 之后執(zhí)行某個邏輯,那么在這一分鐘內(nèi) CPU 會一直存取隊(duì)首元素。所以這里需要借助該對象的wait / notify來解決 while (true) 的忙等問題。

    public MyTimer(){
        thread = new Thread(()->{
           while(true){
               //取出隊(duì)首,如果到時間了就執(zhí)行。
               try {
                   MyTask myTask = queue.take();
                   long curTime = System.currentTimeMillis();
                   if(curTime < myTask.getTime()){
                       queue.put(myTask);
                       //時間未到,不執(zhí)行,這里的 this 表示 MyTimer 對象
                       synchronized (this){
                           //阻塞一段時間
                           this.wait(myTask.getTime() - curTime);
                       }
                   }else {
                       //時間已到,執(zhí)行
                       myTask.run();
                   }
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        });
        thread.start();
    }
    /**
     * 這個方法是用來注冊(添加)任務(wù)的
     * @param runnable 表示待執(zhí)行的任務(wù)
     * @param after 表示多少時間過后執(zhí)行任務(wù)
     */
    public void schedule(Runnable runnable,long after){
        //添加任務(wù),注意這里的時間是 System.currentTimeMillis() + after
        MyTask task = new MyTask(runnable,System.currentTimeMillis() + after);
        queue.put(task);
        synchronized(this){
            this.notify();
        }
    }

修改 Timer schedule 方法,每次有新任務(wù)到來的時候喚醒一下線程。(因?yàn)樾虏迦氲娜蝿?wù)可能是需要馬上執(zhí)行的)。

還沒結(jié)束!上面的代碼還是有缺陷的。假設(shè)當(dāng) thread 線程執(zhí)行完 queue.take() 過后,myTask.getTime() - curTime 的值為 1 個小時。這時 CPU 調(diào)度了其它線程(假設(shè)為 t2) 執(zhí)行, t2 線程調(diào)用 schedule 方法,延時時間為 30 分鐘,并調(diào)用 put 方法,隨后再執(zhí)行 notify 方法。然而這時 wait 方法還沒有執(zhí)行,notify 相當(dāng)于失效了。這時CPU再調(diào)度 thread 線程執(zhí)行,但是 myTask.getTime() - curTime 的值本應(yīng)是 30 分鐘(新添加了一個任務(wù)),但是實(shí)際上卻是 1 個小時。   這是因?yàn)?code>queue.take()與wait不是原子操作,所以才導(dǎo)致這個問題的發(fā)生,下面是改進(jìn)后的代碼。

    public MyTimer(){
        thread = new Thread(()->{
           while(true){
               //取出隊(duì)首,如果到時間了就執(zhí)行。
               try {
                   synchronized (this){
                       MyTask myTask = queue.take();
                       long curTime = System.currentTimeMillis();
                       if(curTime < myTask.getTime()){
                           queue.put(myTask);
                           //時間未到,不執(zhí)行
                           //阻塞一段時間
                           this.wait(myTask.getTime() - curTime);
                       }else {
                           //時間已到,執(zhí)行
                           myTask.run();
                       }                       
                   }
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        });
        thread.start();
    }

2.2 完整代碼

//表示定時器中的任務(wù)
class MyTask implements Comparable<MyTask>{
    //要執(zhí)行的任務(wù)內(nèi)容
    private Runnable runnable;
    //延遲時間
    private long time;
    public MyTask(Runnable runnable, long time) {
        this.runnable = runnable;
        this.time = time;
    }
    //為了便于后面的比較,需要提供 get 方法
    public long getTime() {
        return time;
    }
    //表示任務(wù)開始執(zhí)行
    public void run(){
        this.runnable.run();
    }
    @Override
    public int compareTo(MyTask o) {
        return (int)(this.getTime() - o.getTime());
    }
}
public class MyTimer {
    //掃描線程
    private Thread thread;
    //優(yōu)先級隊(duì)列
    private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();
    public MyTimer(){
        thread = new Thread(()->{
           while(true){
               //取出隊(duì)首,如果到時間了就執(zhí)行。
               try {
                   synchronized (this){
                       MyTask myTask = queue.take();
                       long curTime = System.currentTimeMillis();
                       if(curTime < myTask.getTime()){
                           queue.put(myTask);
                           //時間未到,不執(zhí)行
                           //阻塞一段時間
                           this.wait(myTask.getTime() - curTime);
                       }else {
                           //時間已到,執(zhí)行
                           myTask.run();
                       }
                   }
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        });
        thread.start();
    }
    /**
     * 這個方法是用來注冊(添加)任務(wù)的
     * @param runnable 表示待執(zhí)行的任務(wù)
     * @param after 表示多少時間過后執(zhí)行任務(wù)
     */
    public void schedule(Runnable runnable,long after){
        //添加任務(wù),注意這里的時間是 System.currentTimeMillis() + after
        MyTask task = new MyTask(runnable,System.currentTimeMillis() + after);
        queue.put(task);
        synchronized(this){
            this.notify();
        }
    }
}

以上就是Java中定時器java.util.Timer的簡單模擬的詳細(xì)內(nèi)容,更多關(guān)于Java定時器的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringMVC的@InitBinder參數(shù)轉(zhuǎn)換代碼實(shí)例

    SpringMVC的@InitBinder參數(shù)轉(zhuǎn)換代碼實(shí)例

    這篇文章主要介紹了SpringMVC的@InitBinder參數(shù)轉(zhuǎn)換代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-09-09
  • Java簡單模擬實(shí)現(xiàn)一個線程池

    Java簡單模擬實(shí)現(xiàn)一個線程池

    本文主要介紹了Java簡單模擬實(shí)現(xiàn)一個線程池,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-01-01
  • Java實(shí)現(xiàn)按行分割大文件

    Java實(shí)現(xiàn)按行分割大文件

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)按行分割大文件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • 詳解Spring Boot中如何自定義SpringMVC配置

    詳解Spring Boot中如何自定義SpringMVC配置

    這篇文章主要給大家介紹了關(guān)于Spring Boot中如何自定義SpringMVC配置的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2021-09-09
  • 在SpringBoot中該如何配置攔截器

    在SpringBoot中該如何配置攔截器

    今天給大家?guī)淼氖顷P(guān)于SpringBoot的相關(guān)知識,文章圍繞在SpringBoot中該如何配置攔截器展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • 基于Java內(nèi)存溢出的解決方法詳解

    基于Java內(nèi)存溢出的解決方法詳解

    本篇文章是對Java內(nèi)存溢出的解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • Java創(chuàng)建student類詳細(xì)代碼例子

    Java創(chuàng)建student類詳細(xì)代碼例子

    這篇文章主要給大家介紹了關(guān)于Java創(chuàng)建student類的相關(guān)資料,學(xué)生類(Student)是一種面向?qū)ο蟮木幊谈拍?其主要用于描述學(xué)生的屬性和行為,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11
  • Java實(shí)現(xiàn)圖片轉(zhuǎn)base64完整代碼示例

    Java實(shí)現(xiàn)圖片轉(zhuǎn)base64完整代碼示例

    這篇文章主要給大家介紹了關(guān)于Java實(shí)現(xiàn)圖片轉(zhuǎn)base64的相關(guān)資料,Base64是網(wǎng)絡(luò)上最常見的用于傳輸8Bit字節(jié)碼的編碼方式之一,Base64就是一種基于64個可打印字符來表示二進(jìn)制數(shù)據(jù)的方法,需要的朋友可以參考下
    2023-12-12
  • SpringBoot使用ShardingSphere-Proxy的實(shí)現(xiàn)示例

    SpringBoot使用ShardingSphere-Proxy的實(shí)現(xiàn)示例

    ShardingSphere-Proxy是一個獨(dú)立的數(shù)據(jù)庫代理層,可以與SpringBoot集成,本文介紹了SpringBoot使用ShardingSphere-Proxy的實(shí)現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下
    2025-02-02
  • 使用idea搭建spring項(xiàng)目,利用xml文件的形式進(jìn)行配置方式

    使用idea搭建spring項(xiàng)目,利用xml文件的形式進(jìn)行配置方式

    本文介紹了如何使用SpringIOC和SpringDI的思想開發(fā)一個打印機(jī)模擬程序,實(shí)現(xiàn)了靈活配置彩色墨盒或灰色墨盒以及打印頁面大小的功能,通過創(chuàng)建接口和實(shí)現(xiàn)類,并在配置文件中進(jìn)行依賴注入,實(shí)現(xiàn)了控制反轉(zhuǎn)
    2024-11-11

最新評論

兴海县| 丹凤县| 张掖市| 枝江市| 鄄城县| 谢通门县| 公安县| 株洲市| 西吉县| 闵行区| 贵溪市| 大悟县| 行唐县| 鄂伦春自治旗| 城口县| 姚安县| 平塘县| 荣昌县| 崇左市| 新竹县| 天水市| 常德市| 遵义市| 长沙市| 柳江县| 阿瓦提县| 柘城县| 枞阳县| 张家口市| 嫩江县| 遂宁市| 平阴县| 杭州市| 临邑县| 翼城县| 都匀市| 鸡东县| 顺平县| 临清市| 建阳市| 千阳县|