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

Java中定時(shí)器java.util.Timer的簡(jiǎn)單模擬

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

1.定時(shí)器

1.1 含義

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

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

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

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

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

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

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

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

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

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

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

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

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

//表示定時(shí)器中的任務(wù)
class MyTask implements Comparable<MyTask>{
    //要執(zhí)行的任務(wù)內(nèi)容
    private Runnable runnable;
    //延遲時(shí)間
    private long time;
    public MyTask(Runnable runnable, long time) {
        this.runnable = runnable;
        this.time = time;
    }
    //為了便于后面的比較,需要提供 get 方法
    public long getTime() {
        return time;
    }
    //表示任務(wù)開(kāi)始執(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)先級(jí)隊(duì)列(這里為阻塞隊(duì)列)
    private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();
    /**
     * 這個(gè)方法是用來(lái)注冊(cè)(添加)任務(wù)的
     * @param runnable 表示待執(zhí)行的任務(wù)
     * @param after 表示多少時(shí)間過(guò)后執(zhí)行任務(wù)
     */
    public void schedule(Runnable runnable,long after){
        //添加任務(wù),注意這里的時(shí)間是 System.currentTimeMillis() + after
        MyTask task = new MyTask(runnable,System.currentTimeMillis() + after);
        queue.put(task);
    }
}

5.添加一個(gè)線程來(lái)檢測(cè)隊(duì)首元素:

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

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

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

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

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

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

2.2 完整代碼

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

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

相關(guān)文章

  • SpringBoot前后端接口對(duì)接常見(jiàn)錯(cuò)誤小結(jié)

    SpringBoot前后端接口對(duì)接常見(jiàn)錯(cuò)誤小結(jié)

    SpringBoot前后端接口對(duì)接工作時(shí),經(jīng)常遇到請(qǐng)求500,400等問(wèn)題,本文主要介紹了SpringBoot前后端接口對(duì)接常見(jiàn)錯(cuò)誤小結(jié),感興趣的可以了解一下
    2022-01-01
  • Java并發(fā)編程之LongAdder源碼解析

    Java并發(fā)編程之LongAdder源碼解析

    這篇文章主要為大家介紹了Java并發(fā)編程之LongAdder源碼示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • Springboot 如何設(shè)置啟動(dòng)內(nèi)存

    Springboot 如何設(shè)置啟動(dòng)內(nèi)存

    這篇文章主要介紹了Springboot 如何設(shè)置啟動(dòng)內(nèi)存,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • java數(shù)據(jù)類(lèi)型與變量的安全性介紹

    java數(shù)據(jù)類(lèi)型與變量的安全性介紹

    這篇文章主要介紹了java數(shù)據(jù)類(lèi)型與變量的安全性介紹,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下
    2022-07-07
  • Java實(shí)現(xiàn)摳圖片文字或簽名的完整代碼

    Java實(shí)現(xiàn)摳圖片文字或簽名的完整代碼

    這篇文章主要介紹了java摳圖片文字或簽名的運(yùn)行原理,本文分步驟通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • SpringMVC + jquery.uploadify實(shí)現(xiàn)上傳文件功能

    SpringMVC + jquery.uploadify實(shí)現(xiàn)上傳文件功能

    文件上傳是很多項(xiàng)目都會(huì)使用到的功能,SpringMVC當(dāng)然也提供了這個(gè)功能。不過(guò)小編不建議在項(xiàng)目中通過(guò)form表單來(lái)提交文件上傳,這樣做的局限性很大。下面這篇文章主要介紹了利用SpringMVC + jquery.uploadify實(shí)現(xiàn)上傳文件功能的相關(guān)資料,需要的朋友可以參考下。
    2017-06-06
  • Java List雙擊事件實(shí)現(xiàn)方法

    Java List雙擊事件實(shí)現(xiàn)方法

    這篇文章主要介紹了Java List雙擊事件實(shí)現(xiàn)方法,需要的朋友可以參考下
    2014-09-09
  • java常用工具類(lèi) IP、File文件工具類(lèi)

    java常用工具類(lèi) IP、File文件工具類(lèi)

    這篇文章主要為大家詳細(xì)介紹了java常用工具類(lèi),包括IP、File文件工具類(lèi),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • 基于java實(shí)現(xiàn)人機(jī)猜拳游戲

    基于java實(shí)現(xiàn)人機(jī)猜拳游戲

    這篇文章主要為大家詳細(xì)介紹了基于java實(shí)現(xiàn)人機(jī)猜拳游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • Java多線程之異步Future機(jī)制的原理和實(shí)現(xiàn)

    Java多線程之異步Future機(jī)制的原理和實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了Java多線程之異步Future機(jī)制的原理和實(shí)現(xiàn),感興趣的小伙伴們可以參考一下
    2016-08-08

最新評(píng)論