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

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

 更新時間:2023年07月18日 11:57:05   作者:會飛的喵喵  
在Java中,定時器(Timer)是一個工具類,用于安排任務(wù)在指定時間后執(zhí)行或以指定的時間間隔重復(fù)執(zhí)行,本文就來講講如何簡單模擬實現(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ù)備份、定時生成報表、定時發(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ù)隊列中刪除所有已取消的任務(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.簡單模擬實現(xiàn)定時器

2.1 實現(xiàn)思路

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

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

3.任務(wù)用一個類MyTask來表示,這里需要實現(xiàn)Comparable接口,因為它需要存入優(yōu)先級隊列。其中的屬性:

//表示定時器中的任務(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.實現(xiàn)添加任務(wù)的方法schedule

public class MyTimer {
    //掃描線程
    private Thread thread;
    //優(yōu)先級隊列(這里為阻塞隊列)
    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.添加一個線程來檢測隊首元素:

    //當(dāng)創(chuàng)建對象的時候就直接開啟一個線程
	public MyTimer(){
        thread = new Thread(()->{
           while(true){
               //取出隊首,如果到時間了就執(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();
    }

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

    public MyTimer(){
        thread = new Thread(()->{
           while(true){
               //取出隊首,如果到時間了就執(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ù)到來的時候喚醒一下線程。(因為新插入的任務(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ù)),但是實際上卻是 1 個小時。   這是因為queue.take()wait不是原子操作,所以才導(dǎo)致這個問題的發(fā)生,下面是改進后的代碼。

    public MyTimer(){
        thread = new Thread(()->{
           while(true){
               //取出隊首,如果到時間了就執(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)先級隊列
    private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();
    public MyTimer(){
        thread = new Thread(()->{
           while(true){
               //取出隊首,如果到時間了就執(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)換代碼實例

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

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

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

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

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

    這篇文章主要為大家詳細(xì)介紹了Java實現(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)存溢出的解決方法進行了詳細(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實現(xiàn)圖片轉(zhuǎn)base64完整代碼示例

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

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

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

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

    使用idea搭建spring項目,利用xml文件的形式進行配置方式

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

最新評論

兰坪| 石泉县| 伊通| 仁布县| 石嘴山市| 南雄市| 南投市| 西吉县| 五华县| 赞皇县| 忻州市| 金乡县| 通州区| 六安市| 柳州市| 洱源县| 陕西省| 金坛市| 阜新市| 敦化市| 夏邑县| 平顺县| 龙江县| 珲春市| 怀仁县| 怀柔区| 镇雄县| 白城市| 东莞市| 太原市| 宜城市| 耒阳市| 阿图什市| 吉木萨尔县| 威信县| 共和县| 辰溪县| 宣化县| 邵阳市| 神农架林区| 靖宇县|