国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【JavaEE初階】 定時(shí)器詳解與實(shí)現(xiàn)

這篇具有很好參考價(jià)值的文章主要介紹了【JavaEE初階】 定時(shí)器詳解與實(shí)現(xiàn)。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

??定時(shí)器是什么

【JavaEE初階】 定時(shí)器詳解與實(shí)現(xiàn),JavaEE初階,java-ee,java,開發(fā)語言,多線程,計(jì)算機(jī)操作系統(tǒng),定時(shí)器
定時(shí)器也是軟件開發(fā)中的一個(gè)重要組件. 類似于一個(gè) “鬧鐘”. 達(dá)到一個(gè)設(shè)定的時(shí)間之后, 就執(zhí)行某個(gè)指定好的代碼

定時(shí)器是一種實(shí)際開發(fā)中非常常用的組件.
比如網(wǎng)絡(luò)通信中, 如果對方 500ms 內(nèi)沒有返回?cái)?shù)據(jù), 則斷開連接嘗試重連.
比如一個(gè) Map, 希望里面的某個(gè) key 在 3s 之后過期(自動刪除).
類似于這樣的場景就需要用到定時(shí)器.

??Java標(biāo)準(zhǔn)庫中的定時(shí)器

  • 標(biāo)準(zhǔn)庫中提供了一個(gè) Timer 類. Timer 類的核心方法為 schedule .

  • schedule 包含兩個(gè)參數(shù).

  • 第一個(gè)參數(shù)指定即將要執(zhí)行的任務(wù)代碼,

  • 第二個(gè)參數(shù)指定多長時(shí)間之后執(zhí)行 (單位為毫秒)

代碼示例:

下面程序分別有一個(gè)定時(shí)器,設(shè)置了三個(gè)不同的時(shí)間

import java.util.Timer;
import java.util.TimerTask;

public class TestDemo {
    public static void main(String[] args) {
        Timer timer = new Timer();
        System.out.println("程序啟動!");
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("定時(shí)器3");
            }
        },3000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("定時(shí)器2");
            }
        },2000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("定時(shí)器1");
            }
        },1000);
    }
}

運(yùn)行結(jié)果如下:
【JavaEE初階】 定時(shí)器詳解與實(shí)現(xiàn),JavaEE初階,java-ee,java,開發(fā)語言,多線程,計(jì)算機(jī)操作系統(tǒng),定時(shí)器
結(jié)果如我們所示,按照時(shí)間順序進(jìn)行打印

??模擬實(shí)現(xiàn)定時(shí)器

首先我們先來看一下定時(shí)器的構(gòu)成

??定時(shí)器的構(gòu)成

  1. 一個(gè)帶優(yōu)先級的阻塞隊(duì)列
  • 為啥要帶優(yōu)先級呢?
    因?yàn)樽枞?duì)列中的任務(wù)都有各自的執(zhí)行時(shí)刻 (delay). 最先執(zhí)行的任務(wù)一定是 delay 最小的. 使用帶優(yōu)先級的隊(duì)列就可以高效的把這個(gè) delay 最小的任務(wù)找出來.
  1. 隊(duì)列中的每個(gè)元素是一個(gè) MyTask 對象.

  2. MyTask 中帶有一個(gè)時(shí)間屬性, 隊(duì)首元素就是即將要執(zhí)行的任務(wù)

  3. 同時(shí)有一個(gè)線程一直掃描隊(duì)首元素, 看隊(duì)首元素是否需要執(zhí)行

??第一步:MyStack類的建立

包含兩個(gè)屬性

  • 包含一個(gè) Runnable 對象

  • 一個(gè) time(毫秒時(shí)間戳)

由于我們的MyTask類需要放入一個(gè)帶優(yōu)先級的阻塞隊(duì)列中,所以我們需要MyTack可以比較,這里博主選擇重寫 Comparable 接口里的compareTo方法

代碼實(shí)現(xiàn)如下:

public class MyTask implements Comparable<MyTask> {
    private Runnable runnable;
    private  long time;

    public MyTask() {
        System.out.println(1);
    }
    public void tad() {
        System.out.println(2);
    }
    public MyTask(Runnable runnable, long time) {
        this.runnable = runnable;
        this.time = time;
    }
    public long gettime(MyTask) {
        return this.time;
    }
    //執(zhí)行任務(wù)
    public void run() {
        runnable.run();
    }
    @Override
    public int compareTo(MyTask o) {
        return (int)(this.time - o.time);
    }
}

??第二步:創(chuàng)建MyTimer類

該類需要有一個(gè)帶有優(yōu)先級的阻塞隊(duì)列

還需要有一個(gè)可schedule 方法用于我們來插入我們我們需要執(zhí)行的任務(wù)

public class MyTimer {
    // 有一個(gè)阻塞優(yōu)先級隊(duì)列, 來保存任務(wù).
    private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();

    // 指定兩個(gè)參數(shù)
    // 第一個(gè)參數(shù)是 任務(wù) 內(nèi)容
    // 第二個(gè)參數(shù)是 任務(wù) 在多少毫秒之后執(zhí)行. 形如 1000
    public void schedule(Runnable runnable, long after) {
        // 注意這里的時(shí)間上的換算
        MyTask task = new MyTask(runnable, System.currentTimeMillis() + after);
        queue.put(task);
    }
}
  • 由于我們輸入的都是一個(gè)時(shí)間大小,所以我們需要進(jìn)行處理一下,

  • 這里的System.currentTimeMillis()是獲取當(dāng)時(shí)的時(shí)間戳

  • 再加上所需要的時(shí)間大小即達(dá)到我們效果

其次還需要一個(gè)線程循環(huán)掃描

  • 該掃描我們需要做的是

  • 取出隊(duì)首元素, 檢查看看隊(duì)首元素任務(wù)是否到時(shí)間了.

  • 如果時(shí)間沒到, 就把任務(wù)塞回隊(duì)列里去.

  • 如果時(shí)間到了, 就把任務(wù)進(jìn)行執(zhí)行.

    private Thread t = null;
    public MyTimer() {
        t = new Thread() {
            @Override
            public void run() {
                while (true) {
                    try {
                        // 取出隊(duì)首元素, 檢查看看隊(duì)首元素任務(wù)是否到時(shí)間了.
                        // 如果時(shí)間沒到, 就把任務(wù)塞回隊(duì)列里去.
                        // 如果時(shí)間到了, 就把任務(wù)進(jìn)行執(zhí)行.
                        MyTask myTask = queue.take();
                        long curTime = System.currentTimeMillis();
                        if (curTime < myTask.getTime()) {
                            // 還沒到點(diǎn), 先不必執(zhí)行
                            // 現(xiàn)在是 13:00, 取出來的任務(wù)是 14:00 執(zhí)行
                            //塞回去
                            queue.put(myTask);
                        } else {
                            // 時(shí)間到了!! 執(zhí)行任務(wù)!!
                            myTask.run();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        //啟動線程
        t.start();
    }

??第三步:解決相關(guān)問題

  • 問題一:while (true) 轉(zhuǎn)的太快了, 造成了無意義的 CPU 浪費(fèi).

比如第一個(gè)任務(wù)設(shè)定的是 1 min 之后執(zhí)行某個(gè)邏輯. 但是這里的 while (true) 會導(dǎo)致每秒鐘訪問隊(duì)首元素幾萬次.

解決辦法:引入一個(gè)locker對象, 借助該對象的 wait / notify 來解決 while (true) 的忙等問題.

我們在循環(huán)掃描里:引入 wait, 等待一定的時(shí)間.并修改 MyTimer 的 schedule 方法, 每次有新任務(wù)到來的時(shí)候喚醒一下循環(huán)掃描線程. (因?yàn)樾虏迦氲娜蝿?wù)可能是需要馬上執(zhí)行的)

  • 問題二:原子性問題

由于我們的出隊(duì)列操作和判斷語句不具有原子性

問題情況如下:

出隊(duì)列操作拿到任務(wù)后,還沒有進(jìn)行判斷

然后這時(shí)候有一個(gè)來了一個(gè)新任務(wù)
【JavaEE初階】 定時(shí)器詳解與實(shí)現(xiàn),JavaEE初階,java-ee,java,開發(fā)語言,多線程,計(jì)算機(jī)操作系統(tǒng),定時(shí)器
但是此時(shí)我們該任務(wù)還沒有wait()操作,而且我們由于添加新元素,notify()操作已執(zhí)行,這就導(dǎo)致后面的wait操作不會被喚醒,那么新來的任務(wù)就在相應(yīng)時(shí)間來沒有被執(zhí)行

解決方法:將出隊(duì)列操作與判斷操作都加上鎖

代碼實(shí)現(xiàn)如下:

import java.util.concurrent.PriorityBlockingQueue;

public class MyTimer {
    // 有一個(gè)阻塞優(yōu)先級隊(duì)列, 來保存任務(wù).
    private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();
    // 掃描線程
    private Thread t = null;
    private Object locker = new Object();
    public MyTimer() {
        t = new Thread() {
            @Override
            public void run() {
                while (true) {
                    try {
                        // 取出隊(duì)首元素, 檢查看看隊(duì)首元素任務(wù)是否到時(shí)間了.
                        // 如果時(shí)間沒到, 就把任務(wù)塞回隊(duì)列里去.
                        // 如果時(shí)間到了, 就把任務(wù)進(jìn)行執(zhí)行.
                        synchronized (locker) {
                            MyTask myTask = queue.take();
                            long curTime = System.currentTimeMillis();
                            if (curTime < myTask.getTime()) {
                                // 還沒到點(diǎn), 先不必執(zhí)行
                                // 現(xiàn)在是 13:00, 取出來的任務(wù)是 14:00 執(zhí)行
                                queue.put(myTask);
                                // 在 put 之后, 進(jìn)行一個(gè) wait
                                locker.wait(myTask.getTime() - curTime);
                            } else {
                                // 時(shí)間到了!! 執(zhí)行任務(wù)!!
                                myTask.run();
                            }
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        t.start();
    }
    // 指定兩個(gè)參數(shù)
    // 第一個(gè)參數(shù)是 任務(wù) 內(nèi)容
    // 第二個(gè)參數(shù)是 任務(wù) 在多少毫秒之后執(zhí)行. 形如 1000
    public void schedule(Runnable runnable, long after) {
        // 注意這里的時(shí)間上的換算
        MyTask task = new MyTask(runnable, System.currentTimeMillis() + after);
        queue.put(task);
        synchronized (locker) {
            locker.notify();
        }
    }
}

??完整代碼實(shí)現(xiàn)與測試

計(jì)時(shí)器完整代碼:

import java.util.concurrent.PriorityBlockingQueue;

class MyTask implements Comparable<MyTask> {
    private Runnable runnable;
    private  long time;

    public MyTask() {
        System.out.println(1);
    }
    public void tad() {
        System.out.println(2);
    }
    public MyTask(Runnable runnable, long time) {
        this.runnable = runnable;
        this.time = time;
    }
    public long getTime() {
        return this.time;
    }
    //執(zhí)行任務(wù)
    public void run() {
        runnable.run();
    }
    @Override
    public int compareTo(MyTask o) {
        return (int)(this.time - o.time);
    }
}

public class MyTimer {
    // 有一個(gè)阻塞優(yōu)先級隊(duì)列, 來保存任務(wù).
    private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();
    // 掃描線程
    private Thread t = null;
    private Object locker = new Object();
    public MyTimer() {
        t = new Thread() {
            @Override
            public void run() {
                while (true) {
                    try {
                        // 取出隊(duì)首元素, 檢查看看隊(duì)首元素任務(wù)是否到時(shí)間了.
                        // 如果時(shí)間沒到, 就把任務(wù)塞回隊(duì)列里去.
                        // 如果時(shí)間到了, 就把任務(wù)進(jìn)行執(zhí)行.
                        synchronized (locker) {
                            MyTask myTask = queue.take();
                            long curTime = System.currentTimeMillis();
                            if (curTime < myTask.getTime()) {
                                // 還沒到點(diǎn), 先不必執(zhí)行
                                // 現(xiàn)在是 13:00, 取出來的任務(wù)是 14:00 執(zhí)行
                                queue.put(myTask);
                                // 在 put 之后, 進(jìn)行一個(gè) wait
                                locker.wait(myTask.getTime() - curTime);
                            } else {
                                // 時(shí)間到了!! 執(zhí)行任務(wù)!!
                                myTask.run();
                            }
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        t.start();
    }
    // 指定兩個(gè)參數(shù)
    // 第一個(gè)參數(shù)是 任務(wù) 內(nèi)容
    // 第二個(gè)參數(shù)是 任務(wù) 在多少毫秒之后執(zhí)行. 形如 1000
    public void schedule(Runnable runnable, long after) {
        // 注意這里的時(shí)間上的換算
        MyTask task = new MyTask(runnable, System.currentTimeMillis() + after);
        queue.put(task);
        synchronized (locker) {
            locker.notify();
        }
    }
}

測試代碼如下

public class TestDemo2 {
    public static void main(String[] args) {
        MyTimer myTimer = new MyTimer();
        System.out.println("程序啟動");
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("計(jì)時(shí)器3");
            }
        },3000);
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("計(jì)時(shí)器2");
            }
        },2000);
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("計(jì)時(shí)器1");
            }
        },1000);
    }
}

測試結(jié)果如下:
【JavaEE初階】 定時(shí)器詳解與實(shí)現(xiàn),JavaEE初階,java-ee,java,開發(fā)語言,多線程,計(jì)算機(jī)操作系統(tǒng),定時(shí)器

?總結(jié)

關(guān)于《【JavaEE初階】 定時(shí)器詳解與實(shí)現(xiàn)》就講解到這兒,感謝大家的支持,歡迎各位留言交流以及批評指正,如果文章對您有幫助或者覺得作者寫的還不錯(cuò)可以點(diǎn)一下關(guān)注,點(diǎn)贊,收藏支持一下!文章來源地址http://www.zghlxwxcb.cn/news/detail-736722.html

到了這里,關(guān)于【JavaEE初階】 定時(shí)器詳解與實(shí)現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 51單片機(jī)入門 - 詳解定時(shí)器實(shí)現(xiàn)按鍵控制流水燈方向

    操作系統(tǒng):Windows 10 x84-64 單片機(jī):STC89C52RC 編譯器:SDCC 燒錄軟件:stcgal 1.6 開發(fā)板:普中51單片機(jī)開發(fā)板A2套件(2022) 在 VS Code 中新建項(xiàng)目到燒錄的過程: 左側(cè)EIDE圖標(biāo) - 新建項(xiàng)目 - 空項(xiàng)目 - 8位MCU項(xiàng)目 - 保存文件夾。 更改構(gòu)建配置: SDCC ;更改燒錄配置: stcgal 。 在項(xiàng)目文件

    2024年02月06日
    瀏覽(23)
  • STM32定時(shí)器-定時(shí)器中斷功能詳解

    STM32定時(shí)器-定時(shí)器中斷功能詳解

    STM32的眾多定時(shí)器中我們使用最多的是高級定時(shí)器和通用定時(shí)器,而高級定時(shí)器一般也是用作通用定時(shí)器的功能,下面我們就以通用定時(shí)器為例進(jìn)行講解,其功能和特點(diǎn)包括: 通用與基本定時(shí)器(2~7)位于低速的APB1總線上 高級定時(shí)器(1、8)位于高速的APB2總線上 自動裝載計(jì)

    2024年02月08日
    瀏覽(108)
  • STM32 MCU 定時(shí)器詳解(3)--高級定時(shí)器

    STM32 MCU 定時(shí)器詳解(3)--高級定時(shí)器

    16位遞增、遞減、中心對齊計(jì)數(shù)器(計(jì)數(shù)值:0~65535) 16位預(yù)分頻器(分頻系數(shù):1~65536) 可用于觸發(fā)DAC、ADC 在更新事件、觸發(fā)事件、輸入捕獲、輸出比較時(shí),會產(chǎn)生中斷/DMA請求 4個(gè)獨(dú)立通道,可用于:輸入捕獲、輸出比較、輸出PWM、單脈沖模式 使用外部信號控制定時(shí)器且可實(shí)

    2024年04月17日
    瀏覽(28)
  • STM32 MCU 定時(shí)器詳解(1)--基本定時(shí)器

    STM32 MCU 定時(shí)器詳解(1)--基本定時(shí)器

    定時(shí)器是一種電子組件,主要用于定時(shí)控制,具備精確計(jì)時(shí)的能力。它可以在設(shè)定的時(shí)間間隔內(nèi)觸發(fā)特定的操作,如發(fā)送數(shù)據(jù)、采集傳感器信息、檢測輸入信號或產(chǎn)生規(guī)律性輸出波形。這種靈活性使定時(shí)器在多個(gè)行業(yè)中得到廣泛應(yīng)用,支持各種復(fù)雜功能的實(shí)現(xiàn),是現(xiàn)代電子系

    2024年02月22日
    瀏覽(26)
  • 定時(shí)器詳解 -- 定時(shí)器中斷、PWM輸出 --stm32

    定時(shí)器詳解 -- 定時(shí)器中斷、PWM輸出 --stm32

    STM32F103系列芯片擁有多種定時(shí)器,包括基本定時(shí)器、通用定時(shí)器和高級定時(shí)器,每種定時(shí)器都具有一些特定的功能。 向上計(jì)數(shù):計(jì)數(shù)器從0計(jì)數(shù)到自動重裝載值(ARR),然后重新從0開始計(jì)數(shù)并且產(chǎn)生一個(gè)計(jì)數(shù)器溢出事件。 向下計(jì)數(shù):計(jì)數(shù)器從自動重裝載值(ARR)開始向下計(jì)數(shù)

    2024年02月11日
    瀏覽(24)
  • STM32中TIM定時(shí)器定時(shí)功能詳解(適用基本,通用,高級定時(shí)器)

    STM32中TIM定時(shí)器定時(shí)功能詳解(適用基本,通用,高級定時(shí)器)

    定時(shí)器有高級定時(shí)器、通用定時(shí)器、基本定時(shí)器三種類型。具體功能如下。 上面是每種定時(shí)器所具有的功能。 我們可以看到每種定時(shí)器都有一個(gè)定時(shí)功能,(可能是名字的由來吧)。當(dāng)然,每個(gè)定時(shí)器都可以來使用定時(shí)功能,但是我們往往在基本定時(shí)器和通用定時(shí)器上面使用

    2024年01月19日
    瀏覽(31)
  • 【多線程】定時(shí)器,詳解定時(shí)器原理,讓大家更深刻的理解多線程

    【多線程】定時(shí)器,詳解定時(shí)器原理,讓大家更深刻的理解多線程

    前言: 大家好,我是 良辰丫 ,今天我們一起了解一下定時(shí)器,通過定時(shí)器來熟悉一下線程安全等相關(guān)知識點(diǎn).?????? ??個(gè)人主頁:良辰針不戳 ??所屬專欄:javaEE初階 ??勵(lì)志語句:生活也許會讓我們遍體鱗傷,但最終這些傷口會成為我們一輩子的財(cái)富。 ??期待大家三連,關(guān)注

    2024年02月01日
    瀏覽(27)
  • STM32 定時(shí)器詳解

    STM32 定時(shí)器詳解

    吃了一個(gè)猛虧,自己理解花了大半天時(shí)間,結(jié)果一看代碼發(fā)現(xiàn)巨簡單 算了,把自己理解的放上來吧 目錄 STM32 定時(shí)器詳解 前言 一、定時(shí)器種類和區(qū)分 二、時(shí)鐘源 三、計(jì)數(shù)過程 3.1 計(jì)數(shù)器時(shí)鐘CK_CNT 3.2 計(jì)數(shù)器有關(guān)的三個(gè)寄存器 3.3 其他的寄存器 3.4 定時(shí)器計(jì)算時(shí)間 總結(jié) 前面說

    2024年02月06日
    瀏覽(29)
  • JavaScript的定時(shí)器用法詳解

    ●在 js 里面,有兩種定時(shí)器,倒計(jì)時(shí)定時(shí)器 和 間隔定時(shí)器 ○倒計(jì)時(shí)定時(shí)器也叫一次性定時(shí)器或者叫延時(shí)定時(shí)器 ○間隔定時(shí)器也叫間歇定時(shí)器或者叫反復(fù)性定時(shí)器 倒計(jì)時(shí)定時(shí)器 ●倒計(jì)時(shí)多少時(shí)間以后執(zhí)行函數(shù) ●語法: setTimeout(要執(zhí)行的函數(shù),多長時(shí)間以后執(zhí)行) ●會在你設(shè)

    2024年02月14日
    瀏覽(18)
  • 定時(shí)器 setTimeout、setInterval詳解

    定時(shí)器:按我個(gè)人理解來說就是固定某個(gè)時(shí)間后,時(shí)間到了,就提醒我時(shí)間到了。 程序中的定時(shí)器:相當(dāng)于倒計(jì)時(shí),也相當(dāng)于計(jì)時(shí)器。作用是在設(shè)定的某個(gè)時(shí)間后,執(zhí)行特定的方法。 我們先來了解一下setTimeout定時(shí)器,他的特點(diǎn)就是只能用一次,也稱為一次性定時(shí)器。 接著看

    2023年04月08日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包