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

Java定時(shí)任務(wù)Timer、TimerTask與ScheduledThreadPoolExecutor詳解

 更新時(shí)間:2024年01月23日 09:26:34   作者:碼靈  
這篇文章主要介紹了Java定時(shí)任務(wù)Timer、TimerTask與ScheduledThreadPoolExecutor詳解,  定時(shí)任務(wù)就是在指定時(shí)間執(zhí)行程序,或周期性執(zhí)行計(jì)劃任務(wù),Java中實(shí)現(xiàn)定時(shí)任務(wù)的方法有很多,本文從從JDK自帶的一些方法來(lái)實(shí)現(xiàn)定時(shí)任務(wù)的需求,需要的朋友可以參考下

一、Timer和TimerTask

Timer和TimerTask可以作為線程實(shí)現(xiàn)的常見(jiàn)方式,JDK1.5之后定時(shí)任務(wù)推薦使用ScheduledThreadPoolExecutor。

1、快速入門(mén)

Timer運(yùn)行在后臺(tái),可以執(zhí)行任務(wù)一次,或定期執(zhí)行任務(wù)。TimerTask類(lèi)繼承了Runnable接口,因此具備多線程的能力。

一個(gè)Timer可以調(diào)度任意多個(gè)TimerTask,所有任務(wù)都存儲(chǔ)在一個(gè)隊(duì)列中順序執(zhí)行,如果需要多個(gè)TimerTask并發(fā)執(zhí)行,則需要?jiǎng)?chuàng)建兩個(gè)多個(gè)Timer。

一個(gè)簡(jiǎn)單使用Timer的例子如下:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class TimerTest { 
    //被執(zhí)行的任務(wù)必須繼承TimerTask,并且實(shí)現(xiàn)run方法
    static class MyTimerTask1 extends TimerTask { 
        public void run() { 
            System.out.println("爆炸!?。?); 
        } 
    }    
    public static void main(String[] args) throws ParseException { 
        Timer timer = new Timer(); 
        //1、設(shè)定兩秒后執(zhí)行任務(wù)
        //timer.scheduleAtFixedRate(new MyTimerTask1(), 2000,1000);
        //2、設(shè)定任務(wù)在執(zhí)行時(shí)間執(zhí)行,本例設(shè)定時(shí)間13:57:00
        SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 
        Date time = dateFormatter.parse("2023/02/11 14:40:00"); 
        timer.schedule(new MyTimerTask1(), time);
    } 
} 

2、schedule與scheduleAtFixedRate使用方法

  • schedule(TimerTask task, long delay, long period) --指定任務(wù)執(zhí)行延遲時(shí)間
  • schedule(TimerTask task, Date time, long period) --指定任務(wù)執(zhí)行時(shí)刻
  • scheduleAtFixedRate(TimerTask task, long delay, long period)
  • scheduleAtFixedRate(TimerTask task, Date firstTime, long period)

3、schedule與scheduleAtFixedRate區(qū)別

1) schedule:

①注重任務(wù)執(zhí)行的平滑度,也就是說(shuō)任務(wù)隊(duì)列中某個(gè)任務(wù)執(zhí)行延遲了某個(gè)時(shí)間,接下來(lái)的其余任務(wù)都會(huì)延遲相同時(shí)間,來(lái)最大限度的保證任務(wù)與任務(wù)之間的時(shí)間間隔的完整性;

②當(dāng)程序指定開(kāi)始時(shí)刻(Date time)小于當(dāng)前系統(tǒng)時(shí)刻時(shí),會(huì)立即執(zhí)行一次任務(wù),之后的任務(wù)開(kāi)始執(zhí)行時(shí)間以當(dāng)前時(shí)刻為標(biāo)準(zhǔn),結(jié)合時(shí)間間隔計(jì)算得到;

例:計(jì)劃任務(wù)程序指定從2023/02/11 18:00:00開(kāi)始每隔3分鐘執(zhí)行一次任務(wù)。如果該程序在18:00:00之前運(yùn)行,則計(jì)劃任務(wù)程序分別會(huì)在18:00:00、18:03:00、18:06:00...等時(shí)間點(diǎn)執(zhí)行任務(wù);如果該程序在18:00:00之后運(yùn)行,如在18:07:00時(shí)刻開(kāi)始運(yùn)行程序,計(jì)劃任務(wù)程序判斷指定開(kāi)始執(zhí)行時(shí)刻18:00:00小于當(dāng)前系統(tǒng)時(shí)刻,于是立即執(zhí)行一次任務(wù),接下來(lái)任務(wù)時(shí)間時(shí)刻分別為18:10:00、18:13:00、18:16:00...;而當(dāng)使用scheduleAtFixedRate執(zhí)行計(jì)劃任務(wù)時(shí),無(wú)論計(jì)劃任務(wù)程序在什么時(shí)候運(yùn)行,所有任務(wù)執(zhí)行的次數(shù)都按照原計(jì)劃,不會(huì)因?yàn)槌绦驁?zhí)行時(shí)刻的早晚而改變。而當(dāng)程序運(yùn)行時(shí)刻比計(jì)劃任務(wù)計(jì)劃首次執(zhí)行時(shí)間晚時(shí),如同樣在18:07:00時(shí)刻開(kāi)始執(zhí)行程序,則計(jì)劃任務(wù)程序會(huì)立馬計(jì)算程序執(zhí)行時(shí)刻晚于指定時(shí)刻,會(huì)立即執(zhí)行(18:07:00-18:00:00)/3+1=3次任務(wù)(代表18:00:00、18:03:00和18:06:00三個(gè)時(shí)刻執(zhí)行的任務(wù)),接下來(lái)任務(wù)執(zhí)行時(shí)刻是18:09:00、18:12:00等。

 
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class TimerRateFix {
    public static void main(String[] args) throws ParseException {
        final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 
        Date startDate = dateFormatter.parse("2023/02/11 18:00:00"); 
        Timer timer = new Timer(); 
        timer.schedule(new TimerTask(){ 
           public void run() 
           { 
               System.out.println("執(zhí)行任務(wù),當(dāng)前時(shí)刻:" + dateFormatter.format(new Date())); 
           } 
        },startDate,3*60*1000); 
    }
}

③ 當(dāng)執(zhí)行任務(wù)的時(shí)間間隔t1大于周期間隔t2時(shí),下一次任務(wù)執(zhí)行時(shí)間點(diǎn)相對(duì)于上一次任務(wù)實(shí)際執(zhí)行完成的時(shí)間點(diǎn),每個(gè)任務(wù)的執(zhí)行時(shí)間會(huì)延后,第n個(gè)計(jì)劃任務(wù)的實(shí)際執(zhí)行時(shí)間比預(yù)計(jì)要延后(t1-t2)*n個(gè)時(shí)間單位。

例:計(jì)劃任務(wù)程序指定從2023/02/11 18:00:00開(kāi)始每隔5秒執(zhí)行一次任務(wù),每次任務(wù)執(zhí)行時(shí)間為6秒。當(dāng)程序在18:00:00之前執(zhí)行時(shí),schedule分別會(huì)在18:00:00、18:00:06、18:00:12...等時(shí)間點(diǎn)執(zhí)行計(jì)劃任務(wù),每隔時(shí)間點(diǎn)間隔6秒。原因是根據(jù)計(jì)劃,第一個(gè)計(jì)劃任務(wù)應(yīng)會(huì)在18:00:00執(zhí)行,第二個(gè)計(jì)劃任務(wù)應(yīng)會(huì)在18:00:05執(zhí)行,而在18:00:05時(shí)間點(diǎn),第一個(gè)任務(wù)才執(zhí)行了5秒,還需要1秒才執(zhí)行結(jié)束,因此第二個(gè)任務(wù)不能執(zhí)行,于是等待1秒后在18:00:06時(shí)刻執(zhí)行,之后每個(gè)任務(wù)均如此,均比原定執(zhí)行時(shí)刻有延遲,每個(gè)任務(wù)時(shí)間間隔為6秒。當(dāng)使用scheduleAtFixedRate執(zhí)行計(jì)劃任務(wù)時(shí),第一個(gè)計(jì)劃任務(wù)在18:00:00時(shí)刻執(zhí)行,第二個(gè)會(huì)根據(jù)計(jì)劃在18:00:05執(zhí)行,第三個(gè)會(huì)在18:00:10執(zhí)行,每個(gè)任務(wù)執(zhí)行時(shí)間間隔為5秒,詳細(xì)執(zhí)行情況如下圖所示

圖1 schedule與scheduleAtFixedRate任務(wù)執(zhí)行區(qū)別

import java.text.ParseException; 
import java.text.SimpleDateFormat; 
import java.util.Date; 
import java.util.Timer; 
import java.util.TimerTask; 
public class TimerRateTest { 
    public static void main(String[] args) throws ParseException { 
        final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 
        Timer timer = new Timer(); 
        Date time = dateFormatter.parse("2023/02/11 18:00:00");
        //假設(shè)程序在2023/02/11 18:00:00之前啟動(dòng)
        //1、使用scheduleAtFixedRate,每個(gè)計(jì)劃任務(wù)執(zhí)行時(shí)間點(diǎn)嚴(yán)格為18:00:00、18:00:05、18:00:10...,當(dāng)任務(wù)執(zhí)行時(shí)間大于時(shí)間間隔時(shí)可能會(huì)有并發(fā)情況
        //2、使用schedule,每個(gè)計(jì)劃任務(wù)執(zhí)行時(shí)間點(diǎn)根據(jù)上一個(gè)任務(wù)執(zhí)行結(jié)束時(shí)間及時(shí)間間隔來(lái)計(jì)算
        //     當(dāng)任務(wù)執(zhí)行時(shí)間t1>時(shí)間間隔t2時(shí),第N個(gè)計(jì)劃任務(wù)執(zhí)行時(shí)間點(diǎn)延遲為(t1-t2)*N,執(zhí)行時(shí)間點(diǎn)為18:00:00+t2*(N-1)+(t1-t2)*N
        //    當(dāng)任務(wù)執(zhí)行時(shí)間t1<=時(shí)間間隔t2時(shí),第N個(gè)計(jì)劃任務(wù)執(zhí)行時(shí)間點(diǎn)無(wú)延遲,執(zhí)行時(shí)間為原計(jì)劃
        timer.scheduleAtFixedRate(new TimerTask(){ 
           public void run() { 
               try { 
                   //每個(gè)計(jì)劃任務(wù)執(zhí)行時(shí)間為6秒
                   Thread.sleep(6000); 
               } catch (InterruptedException e) { 
                   e.printStackTrace(); 
               }
               System.out.println("結(jié)束當(dāng)前任務(wù),當(dāng)前時(shí)間:"+ dateFormatter.format(new Date())); 
           } 
        },time,5000);  //計(jì)劃任務(wù)執(zhí)行時(shí)間間隔為5秒
    } 
} 

2)scheduleAtFixedRate:

①注重任務(wù)執(zhí)行的頻度,也就是說(shuō)計(jì)劃任務(wù)程序開(kāi)始執(zhí)行,每隔任務(wù)執(zhí)行的時(shí)間點(diǎn)就已經(jīng)確定,并不會(huì)因?yàn)槟硞€(gè)任務(wù)的延遲而延遲執(zhí)行其他任務(wù),可以保證任務(wù)執(zhí)行的時(shí)間效率;

②當(dāng)程序指定開(kāi)始時(shí)刻(Date firstTime)小于當(dāng)前系統(tǒng)時(shí)刻時(shí),會(huì)立即執(zhí)行任務(wù),執(zhí)行次數(shù)為(當(dāng)前系統(tǒng)時(shí)刻-指定開(kāi)始時(shí)刻)/時(shí)間間隔,之后的任務(wù)開(kāi)始執(zhí)行時(shí)刻與當(dāng)前系統(tǒng)時(shí)刻無(wú)關(guān),仍按照程序指定開(kāi)始時(shí)刻根據(jù)時(shí)間間隔計(jì)算得到;

③當(dāng)執(zhí)行任務(wù)的時(shí)間間隔t1大于周期間隔t2時(shí),下一次任務(wù)執(zhí)行時(shí)間點(diǎn)還是按照原定計(jì)劃不變,加入阻塞隊(duì)列,等待上一個(gè)任務(wù)完成,立即執(zhí)行;只要滿(mǎn)足周期就會(huì)加入阻塞隊(duì)列。

4、終止Timer線程

1) 調(diào)用Timer.cancle()方法??梢栽诔绦蛉魏蔚胤秸{(diào)用,甚至在TimerTask中的run方法中調(diào)用;

2) 創(chuàng)建Timer時(shí)定義位daemon守護(hù)線程,使用new Timer(true)語(yǔ)句;

3) 設(shè)置Timer對(duì)象為null,其會(huì)自動(dòng)終止;

4) 調(diào)用System.exit方法,整個(gè)程序終止。

5、Timer線程的缺點(diǎn)

1) Timer線程不會(huì)捕獲異常,所以TimerTask拋出的未檢查的異常會(huì)終止timer線程。如果Timer線程中存在多個(gè)計(jì)劃任務(wù),其中一個(gè)計(jì)劃任務(wù)拋出未檢查的異常,則會(huì)引起整個(gè)Timer線程結(jié)束,從而導(dǎo)致其他計(jì)劃任務(wù)無(wú)法得到繼續(xù)執(zhí)行?! ?/p>

2) Timer線程時(shí)基于絕對(duì)時(shí)間(如:2023/02/14 16:06:00),因此計(jì)劃任務(wù)對(duì)系統(tǒng)的時(shí)間的改變是敏感的。

3) Timer是單線程,如果某個(gè)任務(wù)很耗時(shí),可能會(huì)影響其他計(jì)劃任務(wù)的執(zhí)行。

因此,JDK1.5以上建議使用ScheduledThreadPoolExecutor來(lái)代替Timer執(zhí)行計(jì)劃任務(wù)?!  ?/p>

二、ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor是JDK1.5以后推出的類(lèi),用于實(shí)現(xiàn)定時(shí)、重復(fù)執(zhí)行的功能,官方文檔解釋要優(yōu)于Timer。

1、構(gòu)造方法  

1)ScheduledThreadPoolExecutor(int corePoolSize) 使用給定核心池大小創(chuàng)建一個(gè)新定定時(shí)線程池

2)ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactorythreadFactory) 使用給定的初始參數(shù)創(chuàng)建一個(gè)新對(duì)象,可提供線程創(chuàng)建工廠

private final static ScheduledThreadPoolExecutor schedual = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
        private AtomicInteger atoInteger = new AtomicInteger(0);
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            t.setName("xxx-Thread "+ atoInteger.getAndIncrement());
            return t;
        }
});

2、調(diào)度方法

1)schedule(Callable callable, long delay, TimeUnit unit); 延遲delay時(shí)間后開(kāi)始執(zhí)行callable

2)scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit); 延遲initialDelay時(shí)間后開(kāi)始執(zhí)行command,并且按照period時(shí)間周期性重復(fù)調(diào)用,當(dāng)任務(wù)執(zhí)行時(shí)間大于間隔時(shí)間時(shí),之后的任務(wù)都會(huì)延遲,此時(shí)與Timer中的scheduleAtFixedRate方法類(lèi)似。

3)scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit); 延遲initialDelay時(shí)間后開(kāi)始執(zhí)行command,并且按照period時(shí)間周期性重復(fù)調(diào)用,這里的間隔時(shí)間delay是等上一個(gè)任務(wù)完全執(zhí)行完畢才開(kāi)始計(jì)算。

圖2 ScheduledThreadPoolExecutor.scheduleWithFixedDelay與Timer.scheduleAtFixedRate任務(wù)執(zhí)行區(qū)別

3、與Timer相比,優(yōu)點(diǎn)

1) ScheduledThreadPoolExecutor線程會(huì)捕獲任務(wù)重的異常,即使多個(gè)計(jì)劃任務(wù)中存在某幾個(gè)計(jì)劃任務(wù)為捕獲異常的情況,也不會(huì)影響ScheduledThreadPoolExecutor總線程的工作,不會(huì)影響其他計(jì)劃任務(wù)的繼續(xù)執(zhí)行。

2)ScheduledThreadPoolExecutor是基于相對(duì)時(shí)間的,對(duì)系統(tǒng)時(shí)間的改變不敏感,但是如果執(zhí)行某一絕對(duì)時(shí)間(如2023/02/14 17:13:06)執(zhí)行任務(wù)(整秒 、整分執(zhí)行任務(wù)),可能不好執(zhí)行,此時(shí)可使用Timer。

3) ScheduledThreadPoolExecutor是線程池,如任務(wù)數(shù)過(guò)多或某些任務(wù)執(zhí)行時(shí)間較長(zhǎng),可自動(dòng)分配更多的線程來(lái)執(zhí)行計(jì)劃任務(wù)。

總之,JDK1.5之后,計(jì)劃任務(wù)建議使用ScheduledThreadPoolExecutor。

到此這篇關(guān)于Java定時(shí)任務(wù)Timer、TimerTask與ScheduledThreadPoolExecutor詳解的文章就介紹到這了,更多相關(guān)Java定時(shí)任務(wù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于java中byte數(shù)組與int類(lèi)型的轉(zhuǎn)換(兩種方法)

    基于java中byte數(shù)組與int類(lèi)型的轉(zhuǎn)換(兩種方法)

    下面小編就為大家?guī)?lái)一篇基于java中byte數(shù)組與int類(lèi)型的轉(zhuǎn)換(兩種方法)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-08-08
  • java實(shí)現(xiàn)猜拳小游戲

    java實(shí)現(xiàn)猜拳小游戲

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)猜拳小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-01-01
  • springCloud中的Sidecar多語(yǔ)言支持詳解

    springCloud中的Sidecar多語(yǔ)言支持詳解

    這篇文章主要介紹了springCloud中的Sidecar多語(yǔ)言支持詳解,Sidecar是將一組緊密結(jié)合的任務(wù)與主應(yīng)用程序共同放在一臺(tái)主機(jī)Host中,但會(huì)將它們部署在各自的進(jìn)程或容器中,需要的朋友可以參考下
    2024-01-01
  • Spring Boot 文件上傳原理解析

    Spring Boot 文件上傳原理解析

    Spring Boot 文件上傳原理其實(shí)就是Spring MVC,因?yàn)檫@部分工作是Spring MVC做的而不是Spring Boot,那么,SpringMVC又是怎么處理文件上傳這個(gè)過(guò)程的呢?下面通過(guò)本文給大家詳細(xì)介紹下,一起看看吧
    2018-03-03
  • Java超詳細(xì)講解ArrayList與順序表的用法

    Java超詳細(xì)講解ArrayList與順序表的用法

    ArrayList 類(lèi)是一個(gè)可以動(dòng)態(tài)修改的數(shù)組,與普通數(shù)組的區(qū)別就是它是沒(méi)有固定大小的限制,我們可以添加或刪除元素。ArrayList 繼承了 AbstractList ,并實(shí)現(xiàn)了 List 接口,順序表是將元素順序地存放在一塊連續(xù)的存儲(chǔ)區(qū)里,元素間的順序關(guān)系由它們的存儲(chǔ)順序自然表示
    2022-06-06
  • IDEA導(dǎo)入eclipse項(xiàng)目并且部署到tomcat的步驟詳解

    IDEA導(dǎo)入eclipse項(xiàng)目并且部署到tomcat的步驟詳解

    這篇文章主要給大家介紹了關(guān)于IDEA導(dǎo)入eclipse項(xiàng)目并且部署到tomcat的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • Java并發(fā)編程中使用Executors類(lèi)創(chuàng)建和管理線程的用法

    Java并發(fā)編程中使用Executors類(lèi)創(chuàng)建和管理線程的用法

    這篇文章主要介紹了Java并發(fā)編程中使用Executors類(lèi)創(chuàng)建和管理線程的用法,文中舉了用其啟動(dòng)線程和設(shè)置線程優(yōu)先級(jí)的例子,需要的朋友可以參考下
    2016-03-03
  • Java利用沙箱支付實(shí)現(xiàn)電腦掃碼支付教程

    Java利用沙箱支付實(shí)現(xiàn)電腦掃碼支付教程

    當(dāng)我們制作的項(xiàng)目需要實(shí)現(xiàn)電腦掃碼支付功能時(shí),我們往往會(huì)采用沙箱支付來(lái)模擬實(shí)現(xiàn)。本文將主要介紹如何在Java中利用沙箱支付實(shí)現(xiàn)這一功能,需要的可以參考一下
    2022-01-01
  • Java8的EnumMap源碼分析

    Java8的EnumMap源碼分析

    這篇文章主要介紹了Java8的EnumMap源碼分析,EnumMap 是一個(gè)用于存儲(chǔ) key 為枚舉類(lèi)型的 map,底層使用數(shù)組實(shí)現(xiàn)(K,V 雙數(shù)組),與其他類(lèi)型 map 不同的是 EnumMap 底層使用雙數(shù)組來(lái)存儲(chǔ) key 與 value,key 數(shù)組會(huì)在構(gòu)造函數(shù)中根據(jù) keyType 進(jìn)行初始化,需要的朋友可以參考下
    2023-11-11
  • SpringBoot配置文件的加載位置實(shí)例詳解

    SpringBoot配置文件的加載位置實(shí)例詳解

    springboot采納了建立生產(chǎn)就緒spring應(yīng)用程序的觀點(diǎn)。 在一些特殊的情況下,我們需要做修改一些配置,或者需要有自己的配置屬性。接下來(lái)通過(guò)本文給大家介紹SpringBoot配置文件的加載位置,感興趣的朋友一起看看吧
    2018-09-09

最新評(píng)論