" />

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

Java任務(wù)定時(shí)執(zhí)行器案例的實(shí)現(xiàn)

 更新時(shí)間:2022年06月06日 14:36:32   作者:未見(jiàn)花聞  
定時(shí)器會(huì)執(zhí)行指定的任務(wù),本文主要介紹了Java任務(wù)定時(shí)執(zhí)行器案例的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

??前面的話??

本篇文章將介紹Java多線程案例,定時(shí)器,定時(shí)器就像鬧鐘一樣,等到了指定的時(shí)間,鬧鐘就會(huì)發(fā)出響聲來(lái)提醒您,而定時(shí)器會(huì)執(zhí)行指定的任務(wù)。

??1.定時(shí)器概述

??1.1認(rèn)識(shí)定時(shí)器

java中的定時(shí)器,也可以叫做任務(wù)定時(shí)執(zhí)行器,顧名思義,就是等到了指定的時(shí)間,就去做指定的事情,就像你每周六或周日都要去力扣參加周賽一樣。

所以你如果想要使用定時(shí)器,你需要交代時(shí)間和對(duì)應(yīng)的任務(wù)才行,java標(biāo)準(zhǔn)也提供了帶有定時(shí)器功能的類Timer。

??1.2Timer類的使用

在java1.8中,Timer給出了四個(gè)構(gòu)造方法,這些構(gòu)造方法可以去指定線程的名字和是否將定時(shí)器內(nèi)部的線程指定為守護(hù)線程。

好了,又出現(xiàn)了一個(gè)新概念,這個(gè)守護(hù)線程是什么鬼?
其實(shí)在java中有兩種線程,一種是用戶線程,另外一種是守護(hù)線程。用戶線程就是普通的線程,守護(hù)線程顧名思義就是守護(hù)用戶線程的線程,可以說(shuō)就是用戶線程的保姆,守護(hù)線程與JVM“共存亡”, 只要存在一個(gè)用戶線程,程序中所有的守護(hù)線程都不會(huì)停止工作,直到最后一個(gè)用戶線程執(zhí)行完畢,守護(hù)線程才會(huì)停止工作。守護(hù)線程最典型的應(yīng)用就是 GC (垃圾回收器),它就是一個(gè)非常稱職的守護(hù)者。

??構(gòu)造方法:

序號(hào)構(gòu)造方法說(shuō)明
1public Timer()無(wú)參數(shù)構(gòu)造方法,默認(rèn)定時(shí)器關(guān)聯(lián)的線程不是守護(hù)線程,線程名字也是默認(rèn)值
2public Timer(boolean isDaemon)指定定時(shí)器中關(guān)聯(lián)的線程是否為守護(hù)線程,如果是,參數(shù)為true
3public Timer(String name)指定定時(shí)器關(guān)聯(lián)線程名稱,線程類型默認(rèn)為非守護(hù)線程
4public Timer(String name, boolean isDaemon)指定定時(shí)器關(guān)聯(lián)線程名和線程類型

Timer類構(gòu)造時(shí)內(nèi)部也會(huì)創(chuàng)建線程,如果不指定,定時(shí)器對(duì)象內(nèi)部的線程(為了簡(jiǎn)化,就稱為關(guān)聯(lián)線程吧)的類型是用戶線程,而不是守護(hù)線程。

??核心方法:

序號(hào)方法說(shuō)明
1public void schedule(TimerTask task, long delay)指定任務(wù),延遲多久執(zhí)行該任務(wù)
2public void schedule(TimerTask task, Date time)指定任務(wù),指定任務(wù)的執(zhí)行時(shí)間
3public void schedule(TimerTask task, long delay, long period)連續(xù)執(zhí)行指定任務(wù),延遲時(shí)間,連續(xù)執(zhí)行任務(wù)的時(shí)間間隔,毫秒為單位
4public void schedule(TimerTask task, Date firstTime, long period)連續(xù)執(zhí)行指定任務(wù),第一次任務(wù)的執(zhí)行時(shí)間,連續(xù)執(zhí)行任務(wù)的時(shí)間間隔
5public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)與方法4作用相同
6public void scheduleAtFixedRate(TimerTask task, long delay, long period)與方法3作用相同
7public void cancel()終止定時(shí)器所有任務(wù),終止執(zhí)行的任務(wù)不受影響

??使用演示:

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.PriorityBlockingQueue;

public class TimeProgram {
    public static void main(String[] args) throws InterruptedException {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("執(zhí)行延后2s執(zhí)行的任務(wù)!");
            }
        }, 2000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("執(zhí)行延后5s執(zhí)行的任務(wù)!");
            }
        }, 5000);

        //每秒輸出一個(gè)mian
        for (int i = 0; i < 5; i++) {
            System.out.println("main");
            Thread.sleep(1000);
        }
    }
}

??運(yùn)行結(jié)果:

TimerTask類就是專門描述定時(shí)器任務(wù)的一個(gè)抽象類,它實(shí)現(xiàn)了Runnable接口。

public abstract class TimerTask implements Runnable    //jdk源碼

下面我們簡(jiǎn)單實(shí)現(xiàn)一下定時(shí)器,我們就不用TimerTask了,我們直接使用Runnable,因?yàn)門imerTask實(shí)現(xiàn)了Runnable接口,所以后面測(cè)試我們自己所寫的schedule方法時(shí),也可以傳入TimerTask類型的引用,既然是簡(jiǎn)單地實(shí)現(xiàn),那就不實(shí)現(xiàn)連續(xù)執(zhí)行的功能了。

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

首先,我們需要建造一個(gè)類,來(lái)描述定時(shí)器的任務(wù),可以使用Runnable加上一個(gè)任務(wù)執(zhí)行的時(shí)間戳就可以了。
??具體清單:
一個(gè)構(gòu)造方法,用來(lái)指定任務(wù)和延遲執(zhí)行時(shí)間。
兩個(gè)獲取方法,用來(lái)給外部對(duì)象獲取該對(duì)象的任務(wù)和執(zhí)行時(shí)間。
實(shí)現(xiàn)比較器,用于定時(shí)器任務(wù)對(duì)象的組織,畢竟,每次需要執(zhí)行時(shí)間最早的任務(wù),需要用到基于小根堆實(shí)現(xiàn)的優(yōu)先隊(duì)列,不,還需要考慮多線程的情況,還是使用優(yōu)先級(jí)阻塞隊(duì)列吧。

//我的任務(wù)
class MyTask implements Comparable<MyTask> {
    //接收具體任務(wù)
    private Runnable runnable;
    //執(zhí)行時(shí)的時(shí)間戳
    private long time;

    //構(gòu)造方法
    public MyTask(Runnable runnable, int delay) {
        this.runnable = runnable;
        this.time = System.currentTimeMillis() + delay;
    }

    //執(zhí)行任務(wù)
    public void run() {
        this.runnable.run();
    }
    //獲取執(zhí)行時(shí)間
    public long getTime() {
        return this.time;
    }

    //實(shí)現(xiàn)comparable接口,方便創(chuàng)建優(yōu)先級(jí)阻塞隊(duì)列
    @Override
    public int compareTo(MyTask o) {
        return (int) (this.time - o.time);
    }
}

接下來(lái)就要實(shí)現(xiàn)定時(shí)器類了,首先我們需要一個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)組織定時(shí)器任務(wù),并且每次都能將時(shí)間最早的任務(wù)找到并執(zhí)行,那么這個(gè)數(shù)據(jù)結(jié)構(gòu)非小根堆莫屬了,也就是優(yōu)先級(jí)隊(duì)列,注意對(duì)自定義類使用優(yōu)先級(jí)隊(duì)列時(shí),一定要實(shí)現(xiàn)比較器。

    //每次執(zhí)行任務(wù)時(shí),需要優(yōu)先執(zhí)行時(shí)間在前的任務(wù),即每次執(zhí)行任務(wù)要選擇時(shí)間戳最小的任務(wù),在多線程情況中優(yōu)先級(jí)阻塞隊(duì)列是最佳選擇
    private static final PriorityBlockingQueue<MyTask> priorityBlockingQueue = new PriorityBlockingQueue<>();

然后,需要一個(gè)方法將任務(wù)安排在優(yōu)先級(jí)阻塞隊(duì)列中,最后在構(gòu)造定時(shí)器對(duì)象的時(shí)候從優(yōu)先級(jí)阻塞隊(duì)列中取任務(wù)并在指定的時(shí)間執(zhí)行。

按照上圖的邏輯,我們自己實(shí)現(xiàn)的定時(shí)器類需要有一個(gè)線程專門去執(zhí)行任務(wù),執(zhí)行任務(wù)過(guò)程中可能會(huì)遇到執(zhí)行時(shí)間還沒(méi)有到的情況,那么線程必須得等待,線程等待的方法有兩種,一種是wait另一種是sleep,這個(gè)案例我們推薦前者,因?yàn)?code>sleep方法不能中途喚醒,這個(gè)案例是有可能需要中途喚醒的,那就是有新任務(wù)插入時(shí),需要重新去優(yōu)先級(jí)阻塞隊(duì)列拿任務(wù)重復(fù)上述操作,這個(gè)喚醒操作可以使用notify方法實(shí)現(xiàn),所以需要用到wait/notify組合拳,既然需要使用wait/notify那么就得有鎖,所以我們可以使用一個(gè)專門的鎖對(duì)象來(lái)加鎖。

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

//我的定時(shí)類 用來(lái)管理任務(wù)
class MyTimer {
    //專門對(duì)鎖對(duì)象
    private final Object locker = new Object();
    //每次執(zhí)行任務(wù)時(shí),需要優(yōu)先執(zhí)行時(shí)間在前的任務(wù),即每次執(zhí)行任務(wù)要選擇時(shí)間戳最小的任務(wù),在多線程情況中優(yōu)先級(jí)阻塞隊(duì)列是最佳選擇
    private static final PriorityBlockingQueue<MyTask> priorityBlockingQueue = new PriorityBlockingQueue<>();

    //安排任務(wù)
    public void schedule(Runnable runnable, int delay) {
        //將任務(wù)放入小根堆中
        MyTask task = new MyTask(runnable, delay);
        priorityBlockingQueue.put(task);
        //每次當(dāng)新任務(wù)加載到阻塞隊(duì)列時(shí),需要中途喚醒線程,因?yàn)樾逻M(jìn)來(lái)的任務(wù)可能是最早需要執(zhí)行的
        synchronized (locker) {
            locker.notify();
        }
    }
    public MyTimer() {
        Thread thread = new Thread(() -> {
            while (true) {
                try {
                    //加載任務(wù),確定執(zhí)行時(shí)機(jī)
                    MyTask myTask = priorityBlockingQueue.take();
                    long curTime = System.currentTimeMillis();
                    //時(shí)間未到,將任務(wù)放回
                    if (curTime < myTask.getTime()) {
                        synchronized (locker) {
                            priorityBlockingQueue.put(myTask);
                            //放回任務(wù)后,不能立即就再次取該任務(wù)加載,需要設(shè)置一個(gè)再次加載的等待時(shí)間,建議使用wait帶參數(shù)的方法
                            //因?yàn)閣ait方法可以使用notify進(jìn)行中途喚醒,而sleep不能中途喚醒
                            int delay = (int)(myTask.getTime() - curTime);
                            locker.wait(delay);
                        }
                    } else {
                        System.out.println(Thread.currentThread().getName() + "線程收到任務(wù),正在執(zhí)行中!");
                        myTask.run();
                        System.out.println(Thread.currentThread().getName() + "線程執(zhí)行任務(wù)完畢,正在等待新任務(wù)!");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        //不要忘了啟動(dòng)線程
        thread.start();
    }
}

??上面是我們實(shí)現(xiàn)定時(shí)器的代碼,我們來(lái)測(cè)試一下:

import java.util.TimerTask;
import java.util.concurrent.PriorityBlockingQueue;

public class TimeProgram {
    public static void main(String[] args) throws InterruptedException {
        MyTimer timer = new MyTimer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("執(zhí)行延后2s執(zhí)行的任務(wù)!");
            }
        }, 2000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("執(zhí)行延后5s執(zhí)行的任務(wù)!");
            }
        }, 5000);

        //每秒輸出一個(gè)mian
        for (int i = 0; i < 5; i++) {
            System.out.println("main");
            Thread.sleep(1000);
        }
    }
}

??執(zhí)行結(jié)果:

好了,任務(wù)定時(shí)執(zhí)行器你學(xué)會(huì)了嗎?

到此這篇關(guān)于Java任務(wù)定時(shí)執(zhí)行器案例的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Java任務(wù)定時(shí)執(zhí)行器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java訪問(wèn)者設(shè)計(jì)模式詳細(xì)講解

    Java訪問(wèn)者設(shè)計(jì)模式詳細(xì)講解

    大多數(shù)情況下你不需要訪問(wèn)者模式,但當(dāng)一旦需要訪問(wèn)者模式時(shí),那就是真的需要它了,這是設(shè)計(jì)模式創(chuàng)始人的原話。可以看出應(yīng)用場(chǎng)景比較少,但需要它的時(shí)候是不可或缺的,這篇文章就開(kāi)始學(xué)習(xí)最后一個(gè)設(shè)計(jì)模式——訪問(wèn)者模式
    2022-11-11
  • 詳解SpringBoot如何優(yōu)雅的處理免登錄接口

    詳解SpringBoot如何優(yōu)雅的處理免登錄接口

    在項(xiàng)目開(kāi)發(fā)過(guò)程中,會(huì)有很多API接口不需要登錄就能直接訪問(wèn),比如公開(kāi)數(shù)據(jù)查詢之類的,常規(guī)處理方法基本是 使用攔截器或過(guò)濾器,攔截需要認(rèn)證的請(qǐng)求路徑,本文介紹一個(gè)更優(yōu)雅的方法自定義注解的方式,文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • Spring 依賴注入的幾種方式詳解

    Spring 依賴注入的幾種方式詳解

    本篇文章主要介紹了Spring 依賴注入的幾種方式詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-02-02
  • ReentrantLock從源碼解析Java多線程同步學(xué)習(xí)

    ReentrantLock從源碼解析Java多線程同步學(xué)習(xí)

    這篇文章主要為大家介紹了ReentrantLock從源碼解析Java多線程同步學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • 深入淺析 Spring Security 緩存請(qǐng)求問(wèn)題

    深入淺析 Spring Security 緩存請(qǐng)求問(wèn)題

    這篇文章主要介紹了 Spring Security 緩存請(qǐng)求問(wèn)題,本文通過(guò)實(shí)例文字相結(jié)合的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2019-04-04
  • Java兩種常用的隨機(jī)數(shù)生成方式(小白總結(jié))

    Java兩種常用的隨機(jī)數(shù)生成方式(小白總結(jié))

    這篇文章主要介紹了Java兩種常用的隨機(jī)數(shù)生成方式(小白總結(jié)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • SpringBoot如何使用applicationContext.xml配置文件

    SpringBoot如何使用applicationContext.xml配置文件

    這篇文章主要介紹了SpringBoot使用applicationContext.xml配置文件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Java實(shí)現(xiàn)Excel導(dǎo)入導(dǎo)出的步驟詳解

    Java實(shí)現(xiàn)Excel導(dǎo)入導(dǎo)出的步驟詳解

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)Excel的導(dǎo)入、導(dǎo)出,文中示例代碼介紹的非常詳細(xì),對(duì)我們的學(xué)習(xí)或工作有一定的幫助,感興趣的小伙伴們可以參考一下
    2023-06-06
  • Spring Boot監(jiān)聽(tīng)Redis Key失效事件實(shí)現(xiàn)定時(shí)任務(wù)的示例

    Spring Boot監(jiān)聽(tīng)Redis Key失效事件實(shí)現(xiàn)定時(shí)任務(wù)的示例

    這篇文章主要介紹了Spring Boot監(jiān)聽(tīng)Redis Key失效事件實(shí)現(xiàn)定時(shí)任務(wù)的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • Spring MVC創(chuàng)建項(xiàng)目踩過(guò)的bug

    Spring MVC創(chuàng)建項(xiàng)目踩過(guò)的bug

    這篇文章主要介紹了Spring MVC創(chuàng)建項(xiàng)目踩過(guò)的bug,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11

最新評(píng)論