亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

1.2 標準庫中的定時器

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.添加一個線程來檢測隊首元素:

    //當創(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è)當 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 相當于失效了。這時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的簡單模擬的詳細內(nèi)容,更多關(guān)于Java定時器的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot前后端接口對接常見錯誤小結(jié)

    SpringBoot前后端接口對接常見錯誤小結(jié)

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

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

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

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

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

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

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

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

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

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

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

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

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

    java常用工具類 IP、File文件工具類

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

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

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

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

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

最新評論