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

Java定時/延時任務之Timer用法詳解

 更新時間:2024年12月15日 10:37:12   作者:JWASX  
在?Java?Development?Kit?(JDK)?中,java.util.Timer?是一個用于調度任務的工具類,本文主要來和大家聊聊Timer的用法,有需要的小伙伴可以了解下

1. 概要

上一篇文章地址:定時/延時任務-自己實現(xiàn)一個簡單的定時器

在上一篇文章中,我們自己實現(xiàn)了一個簡單的 Timer 并提出了一些缺點,下面我們就來看看 JDK 中的 Timer 用法

2. 簡述

在 Java Development Kit (JDK) 中,java.util.Timer 是一個用于調度任務的工具類。Timer 類使用一個后臺線程來遍歷隊列中的任務,同時可以按照固定的延時或者固定的速率來重復執(zhí)行。

首先在介紹 Timer 的 API 之前,先來看兩個概念:

2.1 固定速率

固定速率 策略表示任務在固定的時間間隔內(nèi)重復執(zhí)行,不管任務的執(zhí)行時間有多長,如果任務的執(zhí)行時間超過了時間間隔,那么下一個任務會在當前任務執(zhí)行完畢之后就會馬上開始執(zhí)行,下面是一個例子:假設我們設置了一個固定速率為 5 的任務,從 0s 開始執(zhí)行,也就是說這個任務 5s 執(zhí)行一次:

  • 第一次執(zhí)行: 在 0s 開始執(zhí)行一次,假設執(zhí)行時間是 3s
  • 第二次執(zhí)行: 在 5s 開始執(zhí)行第二次,假設執(zhí)行的時候被阻塞了,執(zhí)行了 8s
  • 第三次執(zhí)行: 在 13s 開始執(zhí)行第三次,假設執(zhí)行的時候被阻塞了,執(zhí)行了 3s
  • 第四次執(zhí)行: 在 16s 開始執(zhí)行第四次,假設執(zhí)行的時候沒有被阻塞
  • 第四次執(zhí)行: 在 20s 開始執(zhí)行第五次,假設執(zhí)行的時候沒有被阻塞

看了上面的過程分析,你可能有點懵,沒關系,等到下面的時候會有例子并解釋

2.2 固定延時

固定延時 策略表示任務在當前任務執(zhí)行完成之后,固定延時一段時間再執(zhí)行下一個任務,下面是一個例子:假設我們設置了一個固定速率為 5 的任務,從 0s 開始執(zhí)行,也就是說這個任務 5s 執(zhí)行一次:

  • 第一次執(zhí)行: 在 0s 開始執(zhí)行一次,假設執(zhí)行時間是 3s
  • 第二次執(zhí)行: 在 5s 開始執(zhí)行第二次,假設執(zhí)行的時候被阻塞了,執(zhí)行了 8s
  • 第三次執(zhí)行: 在 13s 開始執(zhí)行第三次,假設執(zhí)行的時候被阻塞了,執(zhí)行了 3s
  • 第四次執(zhí)行: 在 18s 開始執(zhí)行第四次,假設執(zhí)行的時候沒有被阻塞
  • 第四次執(zhí)行: 在 23s 開始執(zhí)行第五次,假設執(zhí)行的時候沒有被阻塞

2.3 區(qū)別

看了上面兩種方式的分析,可以做一個小的總結:

固定速率: 任務會按照固定時間間隔執(zhí)行,如果任務執(zhí)行的時間大于時間間隔,那么下一個任務會馬上執(zhí)行

固定延時: 任務會按照固定延時執(zhí)行,如果任務執(zhí)行的時間小于時間間隔,那么兩次任務的執(zhí)行時間間隔就是設置的延時;如果任務執(zhí)行的時間大于時間間隔,那么兩次任務執(zhí)行的時間間隔就是任務執(zhí)行的時間,也就是說下一次任務會馬上執(zhí)行

固定速率 這種方式比適合用于嚴格要求按照時間間隔執(zhí)行的任務,比如心跳探測、數(shù)據(jù)收集等…

固定延時 執(zhí)行任務的時間不固定,但是得確保每一次任務執(zhí)行完之后有一定時間間隔再執(zhí)行下一次的任務,比如日志收集、數(shù)據(jù)清理等…

3. Timer 的用法

下面我們就來介紹下 Timer 的幾個 API 的用法

3.1 固定延時 - public void schedule(TimerTask task, long delay, long period)

這個 API 的意思是:延時 delay 后開始按照 period 的間隔執(zhí)行

public class Pra {

    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    System.out.println("Thread-Current: " + Thread.currentThread().getName() + ", time = " + getTime());
                    if(Math.random() < 0.5){
                        System.out.println("sleep: 3s");
                        Thread.sleep(3000);
                    } else {
                        System.out.println("sleep: 8s");
                        Thread.sleep(8000);
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, 0, 5000);
    }

    private static String getTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
        return sdf.format(new Date());
    }

}

輸出結果如下:

3.1.1 解釋

解釋:Timer 源碼中對于任務的添加是線程被喚醒后獲取到任務,之后就會立馬計算出下一次該任務的調度時間加入隊列中

有了上面的基礎再來看輸出,這就是為什么任務執(zhí)行了 3s 最終還是在 49s 就開始執(zhí)行下一個任務,因為 44s 執(zhí)行任務的時候會根據(jù)當前執(zhí)行時間算出下一個任務執(zhí)行時間應該是 44 + 5 = 49s,而第二個任務 49s 執(zhí)行的時候會算出下一個任務執(zhí)行時間是 49 + 5 = 54s,但是由于任務執(zhí)行時間長達 8s,導致下一個任務根本沒時間被調度,所以只能在 57s 執(zhí)行完之后去看隊列,發(fā)現(xiàn)隊列里面 54s 的任務早就到時間了,這時候算出下一個任務的執(zhí)行時間是 57 + 5 = 02s,于是把這個任務加入到隊列中,然后立馬調度這個 54s 的任務,以此類推

你可能會有疑問:如果我任務執(zhí)行時間是 8s,任務間隔是 3s,不會導致執(zhí)行完一個任務之后隊列中會有多個沒有執(zhí)行的任務嗎?并不會,因為固定延時是按照當前時間來算下一個任務的計算時間,所以任務執(zhí)行時間大于任務間隔時間的前提下,不管你間隔多少,都是以任務執(zhí)行時間為主

但是對于固定速率又不一樣了,這個我們下面會說

3.2 固定延時 - public void schedule(TimerTask task, Date firstTime, long period)

顧名思義,就是設置一個第一次啟動的時間點,然后以 period 的延時執(zhí)行,看下面的例子:

public class Pra {

    public static void main(String[] args) {
        Timer timer = new Timer();
        System.out.println("start time = " + getTime());
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    System.out.println("Thread-Current: " + Thread.currentThread().getName() + ", time = " + getTime());
                    if(Math.random() < 0.5){
                        System.out.println("sleep: 3s");
                        Thread.sleep(3000);
                    } else {
                        System.out.println("sleep: 8s");
                        Thread.sleep(8000);
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, new Date(System.currentTimeMillis() + 10000), 5000);
    }

    private static String getTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
        return sdf.format(new Date());
    }

}

上面 3.1 已經(jīng)有解釋了

3.3 固定速率 - public void scheduleAtFixedRate(TimerTask task, long delay, long period)

當前延時 delay 開始,接著每次執(zhí)行的間隔是 period

public class Pra {

    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                try {
                    System.out.println("Thread-Current: " + Thread.currentThread().getName() + ", time = " + getTime());
                    if(Math.random() < 0.5){
                        System.out.println("sleep: 3s");
                        Thread.sleep(3000);
                    } else {
                        System.out.println("sleep: 8s");
                        Thread.sleep(8000);
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, 0, 5000);
    }

    private static String getTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
        return sdf.format(new Date());
    }

}

3.3.1 解釋

1.首先在 27s 開始執(zhí)行第一次,然后往隊列立馬加入一個 32s 的下一次執(zhí)行的任務,當前任務執(zhí)行時間 3s

2. 第二次在 32s 開始執(zhí)行第而次,然后往隊列立馬加入一個 37s 的下一次執(zhí)行的任務,當前任務執(zhí)行時間 8s

3. 第三次執(zhí)行,當 工作線程 執(zhí)行上一個任務之后已經(jīng)到 40s 了,由于 40s 已經(jīng)超過了 37s 的延時任務執(zhí)行時間,于是會立馬開始執(zhí)行,這時候往隊列里面添加一個 42s 執(zhí)行的任務(下一次執(zhí)行)

4. 第四次執(zhí)行,當前任務執(zhí)行時間 3s,執(zhí)行完已經(jīng) 43s 了,這時候執(zhí)行結束會發(fā)現(xiàn)隊列里面的 42s 的任務已經(jīng)過期了,就會往隊列立馬添加一個 47s 的任務(下一次執(zhí)行),然后立馬開始執(zhí)行,所以第四次執(zhí)行時間是 43s

5. 第四次執(zhí)行的時間是 3s ,執(zhí)行完任務是 46s,這時候沒到 47s,所以沒有到下一次任務的執(zhí)行時間,繼續(xù)等待到 47s 執(zhí)行 第五次任務

3.4 固定速率 - public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)

和上面一樣就是選擇某個首次執(zhí)行時間點開始執(zhí)行,后續(xù)速率 period

public class Pra {

    public static void main(String[] args) {
        Timer timer = new Timer();
        System.out.println("start time = " + getTime());
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                try {
                    System.out.println("Thread-Current: " + Thread.currentThread().getName() + ", time = " + getTime());
                    if(Math.random() < 0.5){
                        System.out.println("sleep: 3s");
                        Thread.sleep(3000);
                    } else {
                        System.out.println("sleep: 8s");
                        Thread.sleep(8000);
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, new Date(), 5000);
    }

    private static String getTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
        return sdf.format(new Date());
    }

}

3.5 非周期任務 - public void schedule(TimerTask task, Date time)

上面都是周期任務,下面這兩個就是非周期任務,顧名思義就是只執(zhí)行一次的任務,來看例子:

public class Pra {

    public static void main(String[] args) {
        Timer timer = new Timer();
        System.out.println("start time = " + getTime());
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    System.out.println("Thread-Current: " + Thread.currentThread().getName() + ", time = " + getTime());
                    if(Math.random() < 0.5){
                        System.out.println("sleep: 3s");
                        Thread.sleep(3000);
                    } else {
                        System.out.println("sleep: 8s");
                        Thread.sleep(8000);
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, new Date(System.currentTimeMillis() + 10000));
    }

    private static String getTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
        return sdf.format(new Date());
    }

}

3.6 非周期任務 - schedule(TimerTask task, long delay)

延遲 delay 時間之后開始執(zhí)行

public class Pra {

    public static void main(String[] args) {
        Timer timer = new Timer();
        System.out.println("start time = " + getTime());
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    System.out.println("Thread-Current: " + Thread.currentThread().getName() + ", time = " + getTime());
                    if(Math.random() < 0.5){
                        System.out.println("sleep: 3s");
                        Thread.sleep(3000);
                    } else {
                        System.out.println("sleep: 8s");
                        Thread.sleep(8000);
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, 10000);
    }

    private static String getTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
        return sdf.format(new Date());
    }

}

以上就是Java定時/延時任務之Timer用法詳解的詳細內(nèi)容,更多關于Java Timer用法的資料請關注腳本之家其它相關文章!

相關文章

  • Java實現(xiàn)一個簡單的緩存方法

    Java實現(xiàn)一個簡單的緩存方法

    本篇文章主要介紹了Java實現(xiàn)一個簡單的緩存方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • rabbitmq五種模式詳解(含實現(xiàn)代碼)

    rabbitmq五種模式詳解(含實現(xiàn)代碼)

    這篇文章主要介紹了rabbitmq五種模式詳解(含實現(xiàn)代碼),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • Java反射機制用法總結

    Java反射機制用法總結

    反射機制是在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態(tài)獲取的信息以及動態(tài)調用對象的方法的功能稱為java語言的反射機制。下面我們來一起學習一下吧
    2019-05-05
  • java實現(xiàn)mongodb的數(shù)據(jù)庫連接池

    java實現(xiàn)mongodb的數(shù)據(jù)庫連接池

    這篇文章主要介紹了基于java實現(xiàn)mongodb的數(shù)據(jù)庫連接池,Java通過使用mongo-2.7.3.jar包實現(xiàn)mongodb連接池,感興趣的小伙伴們可以參考一下
    2015-12-12
  • 淺談java中String與StringBuffer的不同

    淺談java中String與StringBuffer的不同

    String在棧中,StringBuffer在堆中!所以String是不可變的,數(shù)據(jù)是共享的。StringBuffer都是獨占的,是可變的(因為每次都是創(chuàng)建新的對象!)
    2015-11-11
  • Java多線程——之一創(chuàng)建線程的四種方法

    Java多線程——之一創(chuàng)建線程的四種方法

    這篇文章主要介紹了Java創(chuàng)建線程方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04
  • Java跳出多重嵌套循環(huán)代碼實例

    Java跳出多重嵌套循環(huán)代碼實例

    這篇文章主要介紹了Java跳出多重嵌套循環(huán),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-03-03
  • Java生成遞增流水號(編號+時間+流水號)簡單示例

    Java生成遞增流水號(編號+時間+流水號)簡單示例

    這篇文章主要給大家介紹了關于Java生成遞增流水號(編號+時間+流水號)的相關資料,在開發(fā)項目漫長的過程中常常會遇到流水號需要自動生成的問題存在,文中給出了詳細的代碼示例,需要的朋友可以參考下
    2023-07-07
  • Java 時間格式轉換之impleDateFormat與Data API解析與使用

    Java 時間格式轉換之impleDateFormat與Data API解析與使用

    想必大家對 SimpleDateFormat 并不陌生。SimpleDateFormat 是 Java 中一個非常常用的類,他是以區(qū)域敏感的方式格式化和解析日期的具體類。 它允許格式化 (date -> text)、語法分析 (text -> date)和標準化
    2021-11-11
  • Java函數(shù)式編程(十):收集器

    Java函數(shù)式編程(十):收集器

    這篇文章主要介紹了Java函數(shù)式編程(十):收集器,本文是系列文章的第10篇,其它文章請參閱本文底部的相關文章,需要的朋友可以參考下
    2014-09-09

最新評論