最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文搞懂Java?ScheduledExecutorService的使用

 更新時間:2022年11月02日 11:16:24   作者:UnicornLien  
JUC包(java.util.concurrent)中提供了對定時任務(wù)的支持,即ScheduledExecutorService接口。本文主要對ScheduledExecutorService的使用進(jìn)行簡單的介紹,需要的可以參考一下

JUC包(java.util.concurrent)中提供了對定時任務(wù)的支持,即ScheduledExecutorService接口。

本文對ScheduledExecutorService的介紹,將基于Timer類使用介紹進(jìn)行,因此請先閱讀Timer類使用介紹文章。

此處為語雀內(nèi)容卡片,點擊鏈接查看

一、創(chuàng)建ScheduledExecutorService對象

ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);

二、ScheduledExecutorService方法

ScheduledExecutorService實現(xiàn)了ExecutorService接口,ExecutorService接口中的方法事實上屬于線程池相關(guān)的一般方法,不在本文討論。

ScheduledExecutorService本身提供了以下4個方法:

  • ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit):延遲delay單位時間后,執(zhí)行一次任務(wù)
  • <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit):延遲delay單位時間后,執(zhí)行一次任務(wù)
  • ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit):延遲initialDelay單位時間后,執(zhí)行一次任務(wù),之后每隔period單位時間執(zhí)行一次任務(wù)(固定速率)
  • ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit):延遲initialDelay單位時間后,執(zhí)行一次任務(wù),之后每隔period單位時間執(zhí)行一次任務(wù)(固定延時)

ScheduledExecutorService和Timer進(jìn)行對比,兩者所提供的方法是類似的,區(qū)別在于Timer有提供指定時間點執(zhí)行任務(wù),而ScheduledExecutorService沒有提供。

Timer提供的方法返回值均為void,而ScheduledExecutorService的方法返回值均為ScheduledFuture(繼承于Future接口)。

三、固定速率和固定延時的區(qū)別

和Timer一樣,我們用示例來展示ScheduledExecutorService固定速率和固定延時的區(qū)別,并與Timer進(jìn)行對比。

1. 固定速率

示例:

System.out.println("啟動于:" + DateUtil.formatNow());
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
executorService.scheduleAtFixedRate(
        new Runnable() {
            int i = 1;
            @Override
            public void run() {
                System.out.print(i + " " + DateUtil.formatNow() + " 開始執(zhí)行, ");
                if(i == 3) {
                    ThreadUtil.sleep(11 * 1000);
                }
                System.out.println(DateUtil.formatNow() + " 結(jié)束");
                i ++;
            }
        },
5, 2, TimeUnit.SECONDS);

輸出:

啟動于:2022-10-31 17:15:44
1 2022-10-31 17:15:49 開始執(zhí)行, 2022-10-31 17:15:49 結(jié)束
2 2022-10-31 17:15:51 開始執(zhí)行, 2022-10-31 17:15:51 結(jié)束
3 2022-10-31 17:15:53 開始執(zhí)行, 2022-10-31 17:16:04 結(jié)束 *
4 2022-10-31 17:16:04 開始執(zhí)行, 2022-10-31 17:16:04 結(jié)束 *
5 2022-10-31 17:16:04 開始執(zhí)行, 2022-10-31 17:16:04 結(jié)束 *
6 2022-10-31 17:16:04 開始執(zhí)行, 2022-10-31 17:16:04 結(jié)束 *
7 2022-10-31 17:16:04 開始執(zhí)行, 2022-10-31 17:16:04 結(jié)束 *
8 2022-10-31 17:16:04 開始執(zhí)行, 2022-10-31 17:16:04 結(jié)束 *
9 2022-10-31 17:16:05 開始執(zhí)行, 2022-10-31 17:16:05 結(jié)束
10 2022-10-31 17:16:07 開始執(zhí)行, 2022-10-31 17:16:07 結(jié)束
11 2022-10-31 17:16:09 開始執(zhí)行, 2022-10-31 17:16:09 結(jié)束

沒有11秒耗時的情況下,正常應(yīng)該是輸出:

啟動于:2022-10-31 17:15:44
1 2022-10-31 17:15:49 開始執(zhí)行, 2022-10-31 17:15:49 結(jié)束
2 2022-10-31 17:15:51 開始執(zhí)行, 2022-10-31 17:15:51 結(jié)束
3 2022-10-31 17:15:53 開始執(zhí)行, 2022-10-31 17:15:53 結(jié)束
4 2022-10-31 17:15:55 開始執(zhí)行, 2022-10-31 17:15:55 結(jié)束
5 2022-10-31 17:15:57 開始執(zhí)行, 2022-10-31 17:15:57 結(jié)束
6 2022-10-31 17:15:59 開始執(zhí)行, 2022-10-31 17:15:59 結(jié)束
7 2022-10-31 17:16:01 開始執(zhí)行, 2022-10-31 17:16:01 結(jié)束
8 2022-10-31 17:16:03 開始執(zhí)行, 2022-10-31 17:16:03 結(jié)束
9 2022-10-31 17:16:05 開始執(zhí)行, 2022-10-31 17:16:05 結(jié)束
10 2022-10-31 17:16:07 開始執(zhí)行, 2022-10-31 17:16:07 結(jié)束
11 2022-10-31 17:16:09 開始執(zhí)行, 2022-10-31 17:16:09 結(jié)束

從測試結(jié)果中可以看出,當(dāng)有一次任務(wù)執(zhí)行耗時過長,超出了設(shè)定的period時間單位,將會影響后續(xù)5次任務(wù)準(zhǔn)時執(zhí)行,當(dāng)耗時任務(wù)完成后,ScheduledExecutorService將會立即將延誤的5次任務(wù)一起補(bǔ)上,并保障后續(xù)的任務(wù)按預(yù)期的時間點執(zhí)行。

這與ScheduledExecutorService固定速率的效果與Timer是完全一樣的,讀者可直接參考Timer的固定速率介紹。

2. 固定延時

示例:

System.out.println("啟動于:" + DateUtil.formatNow());
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
executorService.scheduleWithFixedDelay(
        new Runnable() {
            int i = 1;
            @Override
            public void run() {
                System.out.print(i + " " + DateUtil.formatNow() + " 開始執(zhí)行, ");
                if(i == 3) {
                    ThreadUtil.sleep(11 * 1000);
                }
                System.out.println(DateUtil.formatNow() + " 結(jié)束");
                i ++;
            }
        },
5, 2, TimeUnit.SECONDS);

輸出:

1 2022-10-31 17:16:41 開始執(zhí)行, 2022-10-31 17:16:41 結(jié)束
2 2022-10-31 17:16:43 開始執(zhí)行, 2022-10-31 17:16:43 結(jié)束
3 2022-10-31 17:16:45 開始執(zhí)行, 2022-10-31 17:16:56 結(jié)束 *
4 2022-10-31 17:16:58 開始執(zhí)行, 2022-10-31 17:16:58 結(jié)束
5 2022-10-31 17:17:00 開始執(zhí)行, 2022-10-31 17:17:00 結(jié)束
6 2022-10-31 17:17:02 開始執(zhí)行, 2022-10-31 17:17:02 結(jié)束
7 2022-10-31 17:17:04 開始執(zhí)行, 2022-10-31 17:17:04 結(jié)束
8 2022-10-31 17:17:06 開始執(zhí)行, 2022-10-31 17:17:06 結(jié)束
9 2022-10-31 17:17:08 開始執(zhí)行, 2022-10-31 17:17:08 結(jié)束

沒有11秒耗時的情況下,正常應(yīng)該是輸出:

1 2022-10-31 17:16:41 開始執(zhí)行, 2022-10-31 17:16:41 結(jié)束
2 2022-10-31 17:16:43 開始執(zhí)行, 2022-10-31 17:16:43 結(jié)束
3 2022-10-31 17:16:45 開始執(zhí)行, 2022-10-31 17:16:45 結(jié)束
4 2022-10-31 17:16:47 開始執(zhí)行, 2022-10-31 17:16:47 結(jié)束
5 2022-10-31 17:16:49 開始執(zhí)行, 2022-10-31 17:16:49 結(jié)束
6 2022-10-31 17:16:51 開始執(zhí)行, 2022-10-31 17:16:51 結(jié)束
7 2022-10-31 17:16:53 開始執(zhí)行, 2022-10-31 17:16:53 結(jié)束
8 2022-10-31 17:16:55 開始執(zhí)行, 2022-10-31 17:16:55 結(jié)束
9 2022-10-31 17:16:57 開始執(zhí)行, 2022-10-31 17:16:57 結(jié)束

固定延時是當(dāng)任務(wù)執(zhí)行耗時過長,超出設(shè)定的delay時間單位,后續(xù)的任務(wù)將會被順延推遲,這個設(shè)計是與Timer一樣的,但與Timer卻有一點小區(qū)別。

在Timer類使用介紹中,曾提到Timer類固定延時下與我想象的不太一致,Timer在第3次任務(wù)執(zhí)行完成后會立即執(zhí)行第4次任務(wù),接著才是間隔2秒執(zhí)行第5次任務(wù)。

而ScheduledExecutorService則與我的想象完全一致,當(dāng)?shù)?次任務(wù)執(zhí)行完成后,會間隔2秒再執(zhí)行第4次任務(wù)。

所以固定延時下,Timer和ScheduledExecutorService的實現(xiàn)是有一點區(qū)別的。

四、調(diào)度多個任務(wù)

在Timer中,一個TimerTask對象是一個任務(wù)。

而在ScheduledExecutorService中,則一個Runnable對象一個任務(wù)。

第三節(jié)介紹的是固定速率和固定延時是如何影響一個可重復(fù)執(zhí)行任務(wù)(一個Runnable對象)的多次執(zhí)行的。

而本節(jié)介紹的是ScheduledExecutorService如何同時調(diào)度多個可重復(fù)執(zhí)行任務(wù)的。

與Timer內(nèi)部僅1個線程不同,ScheduledExecutorService內(nèi)部采用的是線程池,是支持自己設(shè)定線程數(shù)的。

那么理論上來說,如果要加入2個任務(wù),ScheduledExecutorService設(shè)定線程數(shù)為2,就不會出現(xiàn)相互影響的情況。

我們來驗證一下。

定義任務(wù),當(dāng)執(zhí)行第3次時將會休眠11秒:

class Task implements Runnable {

    private int i = 1;

    private String name;

    public Task(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(i + " " + name + ":" + DateUtil.formatNow() + " 開始執(zhí)行");
        if(i == 3) {
            ThreadUtil.sleep(11 * 1000);
        }
        System.out.println(i + " " + name + ":" + DateUtil.formatNow() + " 執(zhí)行結(jié)束");
        i ++;
    }
}

使用ScheduledExecutorService進(jìn)行調(diào)度:

System.out.println("啟動于:" + DateUtil.formatNow());
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);

Task task1 = new Task("task1");
Task task2 = new Task("task2");

executorService.scheduleWithFixedDelay(task1, 5, 2, TimeUnit.SECONDS);
executorService.scheduleWithFixedDelay(task2, 5, 2, TimeUnit.SECONDS);

由于控制臺輸出時,task1和task2的日志會混在一起,不容易閱讀,我這邊將task1和task2的日志分開。

task1日志:

啟動于:2022-10-31 17:49:51
1 task1:2022-10-31 17:49:56 開始執(zhí)行
1 task1:2022-10-31 17:49:56 執(zhí)行結(jié)束
2 task1:2022-10-31 17:49:58 開始執(zhí)行
2 task1:2022-10-31 17:49:58 執(zhí)行結(jié)束
3 task1:2022-10-31 17:50:00 開始執(zhí)行
3 task1:2022-10-31 17:50:11 執(zhí)行結(jié)束
4 task1:2022-10-31 17:50:13 開始執(zhí)行
4 task1:2022-10-31 17:50:13 執(zhí)行結(jié)束
5 task1:2022-10-31 17:50:15 開始執(zhí)行
5 task1:2022-10-31 17:50:15 執(zhí)行結(jié)束

task2日志:

啟動于:2022-10-31 17:49:51
1 task2:2022-10-31 17:49:56 開始執(zhí)行
1 task2:2022-10-31 17:49:56 執(zhí)行結(jié)束
2 task2:2022-10-31 17:49:58 開始執(zhí)行
2 task2:2022-10-31 17:49:58 執(zhí)行結(jié)束
3 task2:2022-10-31 17:50:00 開始執(zhí)行
3 task2:2022-10-31 17:50:11 執(zhí)行結(jié)束
4 task2:2022-10-31 17:50:13 開始執(zhí)行
4 task2:2022-10-31 17:50:13 執(zhí)行結(jié)束
5 task2:2022-10-31 17:50:15 開始執(zhí)行

經(jīng)過測試可以確定,當(dāng)加入的任務(wù)數(shù)不超過線程池線程數(shù)時,即使任務(wù)存在耗時也不會相互影響,而僅是影響自身任務(wù)下一次執(zhí)行的時間點。

那如果加入任務(wù)數(shù)超出了線程數(shù)呢?

我們測試一下加入3個任務(wù),線程數(shù)仍然為2.

Task task1 = new Task("task1");
Task task2 = new Task("task2");
Task task3 = new Task("task3");

executorService.scheduleWithFixedDelay(task1, 5, 2, TimeUnit.SECONDS);
executorService.scheduleWithFixedDelay(task2, 5, 2, TimeUnit.SECONDS);
executorService.scheduleWithFixedDelay(task3, 5, 2, TimeUnit.SECONDS);

將三個任務(wù)的日志分開展示。

task1:

啟動于:2022-10-31 17:53:22
1 task1:2022-10-31 17:53:27 開始執(zhí)行
1 task1:2022-10-31 17:53:27 執(zhí)行結(jié)束
2 task1:2022-10-31 17:53:29 開始執(zhí)行
2 task1:2022-10-31 17:53:29 執(zhí)行結(jié)束
3 task1:2022-10-31 17:53:31 開始執(zhí)行
3 task1:2022-10-31 17:53:42 執(zhí)行結(jié)束
4 task1:2022-10-31 17:53:44 開始執(zhí)行
4 task1:2022-10-31 17:53:44 執(zhí)行結(jié)束
5 task1:2022-10-31 17:53:46 開始執(zhí)行
5 task1:2022-10-31 17:53:46 執(zhí)行結(jié)束
6 task1:2022-10-31 17:53:48 開始執(zhí)行
6 task1:2022-10-31 17:53:48 執(zhí)行結(jié)束
7 task1:2022-10-31 17:53:50 開始執(zhí)行
7 task1:2022-10-31 17:53:50 執(zhí)行結(jié)束
8 task1:2022-10-31 17:53:52 開始執(zhí)行
8 task1:2022-10-31 17:53:52 執(zhí)行結(jié)束
9 task1:2022-10-31 17:53:54 開始執(zhí)行
9 task1:2022-10-31 17:53:54 執(zhí)行結(jié)束
10 task1:2022-10-31 17:53:56 開始執(zhí)行
10 task1:2022-10-31 17:53:56 執(zhí)行結(jié)束

task2:

啟動于:2022-10-31 17:53:22
1 task2:2022-10-31 17:53:27 開始執(zhí)行
1 task2:2022-10-31 17:53:27 執(zhí)行結(jié)束
2 task2:2022-10-31 17:53:29 開始執(zhí)行
2 task2:2022-10-31 17:53:29 執(zhí)行結(jié)束
3 task2:2022-10-31 17:53:31 開始執(zhí)行
3 task2:2022-10-31 17:53:42 執(zhí)行結(jié)束
4 task2:2022-10-31 17:53:44 開始執(zhí)行
4 task2:2022-10-31 17:53:44 執(zhí)行結(jié)束
5 task2:2022-10-31 17:53:46 開始執(zhí)行
5 task2:2022-10-31 17:53:46 執(zhí)行結(jié)束
6 task2:2022-10-31 17:53:48 開始執(zhí)行
6 task2:2022-10-31 17:53:48 執(zhí)行結(jié)束
7 task2:2022-10-31 17:53:50 開始執(zhí)行
7 task2:2022-10-31 17:53:50 執(zhí)行結(jié)束
8 task2:2022-10-31 17:53:52 開始執(zhí)行
8 task2:2022-10-31 17:53:52 執(zhí)行結(jié)束
9 task2:2022-10-31 17:53:54 開始執(zhí)行
9 task2:2022-10-31 17:53:54 執(zhí)行結(jié)束
10 task2:2022-10-31 17:53:56 開始執(zhí)行
10 task2:2022-10-31 17:53:56 執(zhí)行結(jié)束

task3:

啟動于:2022-10-31 17:53:22
1 task3:2022-10-31 17:53:27 開始執(zhí)行
1 task3:2022-10-31 17:53:27 執(zhí)行結(jié)束
2 task3:2022-10-31 17:53:29 開始執(zhí)行
2 task3:2022-10-31 17:53:29 執(zhí)行結(jié)束
3 task3:2022-10-31 17:53:42 開始執(zhí)行
3 task3:2022-10-31 17:53:53 執(zhí)行結(jié)束
4 task3:2022-10-31 17:53:55 開始執(zhí)行
4 task3:2022-10-31 17:53:55 執(zhí)行結(jié)束
5 task3:2022-10-31 17:53:57 開始執(zhí)行
5 task3:2022-10-31 17:53:57 執(zhí)行結(jié)束

從以上日志可以看出,task1和task2執(zhí)行是正常的,但是task3從第3次執(zhí)行開始出現(xiàn)錯誤。

task3第三次時間點正確時間應(yīng)該是17:53:31,而實際上被推遲到了17:53:42才開始。

從這點我們可以推測出,當(dāng)時2個線程都在執(zhí)行task1、task2的耗時11秒的第3次任務(wù),導(dǎo)致task3被推遲。

因此,我們在使用ScheduledExecutorService調(diào)度多個任務(wù)時,應(yīng)注意盡可能縮短任務(wù)的處理耗時,以及避免任務(wù)數(shù)超出線程數(shù)。

五、其他要點

任務(wù)執(zhí)行過程中拋出異常會發(fā)生什么情況?

Timer內(nèi)部是單個線程處理所有任務(wù),當(dāng)拋出異常時,Timer線程將終止運行;

ScheduledExecutorService內(nèi)部是一個線程池,當(dāng)拋出異常時,此任務(wù)所在線程將會終止運行被回收,該任務(wù)后續(xù)無法再觸發(fā)執(zhí)行,其他線程不受影響,因此編寫任務(wù)執(zhí)行代碼要注意捕獲異常。

以上就是一文搞懂Java ScheduledExecutorService的使用的詳細(xì)內(nèi)容,更多關(guān)于Java ScheduledExecutorService的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java中 String和StringBuffer的區(qū)別實例詳解

    java中 String和StringBuffer的區(qū)別實例詳解

    這篇文章主要介紹了java中 String和StringBuffer的區(qū)別實例詳解的相關(guān)資料,一個小的例子,來測試String和StringBuffer在時間和空間使用上的差別,需要的朋友可以參考下
    2017-04-04
  • mybatis快速入門學(xué)習(xí)教程新手注意問題小結(jié)

    mybatis快速入門學(xué)習(xí)教程新手注意問題小結(jié)

    MyBatis 是支持定制化 SQL、存儲過程以及高級映射的優(yōu)秀的持久層框架。接下來通過本文給大家介紹mybatis快速入門學(xué)習(xí)教程新手注意問題小結(jié),需要的朋友可以參考下
    2017-02-02
  • springboot接口接收數(shù)組及多個參數(shù)的問題及解決

    springboot接口接收數(shù)組及多個參數(shù)的問題及解決

    這篇文章主要介紹了springboot接口接收數(shù)組及多個參數(shù)的問題及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Java設(shè)計模式之觀察者模式_動力節(jié)點Java學(xué)院整理

    Java設(shè)計模式之觀察者模式_動力節(jié)點Java學(xué)院整理

    這篇文章給大家介紹流量java設(shè)計模式之觀察者模式,定義對象間一種一對多的依賴關(guān)系,使得當(dāng)每一個對象改變狀態(tài)。下面通過類圖和實例代碼給大家介紹java設(shè)計模式之觀察者模式,感興趣的朋友一起看看吧
    2017-08-08
  • Java圖文分析之繼承內(nèi)存布局

    Java圖文分析之繼承內(nèi)存布局

    這篇文章主要介紹了Java圖文分析之繼承內(nèi)存布局,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,感興趣的朋友可以參考一下
    2022-09-09
  • Intellij IDEA 斷點不可用報錯 No executable code found

    Intellij IDEA 斷點不可用報錯 No executable 

    這篇文章主要介紹了Intellij IDEA 斷點不可用報錯 No executable code found問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • Spring Cloud微服務(wù)使用webSocket的方法

    Spring Cloud微服務(wù)使用webSocket的方法

    WebSocket在現(xiàn)代瀏覽器中的應(yīng)用已經(jīng)算是比較普遍了,在某些業(yè)務(wù)場景下,要求必須能夠在服務(wù)器端推送消息至客戶端,本文給大家介紹Spring Cloud微服務(wù)使用webSocket的方法,感興趣的朋友一起看看吧
    2021-06-06
  • 詳解Spring注解--@Autowired、@Resource和@Service

    詳解Spring注解--@Autowired、@Resource和@Service

    本篇文章主要介紹最重要的三個Spring注解,也就是@Autowired、@Resource和@Service,具有很好的參考價值。下面跟著小編一起來看下吧
    2017-05-05
  • IDEA?2022最新激活碼注冊碼超詳細(xì)教程(親測激活有效)

    IDEA?2022最新激活碼注冊碼超詳細(xì)教程(親測激活有效)

    這篇文章主要介紹了IDEA?2022最新激活碼超詳細(xì)教程(親測激活至2099年),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • SpringFox實現(xiàn)自動生成RESTful?API文檔

    SpringFox實現(xiàn)自動生成RESTful?API文檔

    在開發(fā)?RESTful?API?時,編寫?API?文檔是一個重要的任務(wù),這篇文章為大家介紹了如何使用?SpringFox?自動生成?RESTful?API?文檔,并提供示例代碼,需要的可以參考一下
    2023-06-06

最新評論

广元市| 伊春市| 峨山| 乐安县| 桐城市| 洛扎县| 广饶县| 依兰县| 浮梁县| 清苑县| 望城县| 新闻| 安新县| 叶城县| 大理市| 乌鲁木齐市| 淄博市| 葵青区| 红安县| 朔州市| 桃园县| 伽师县| 哈密市| 天水市| 滨州市| 枞阳县| 灵川县| 锡林郭勒盟| 维西| 蕲春县| 九江市| 东丽区| 青神县| 涿鹿县| 海原县| 临夏县| 陆川县| 上杭县| 孝昌县| 土默特右旗| 通江县|