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

Java定時任務的三種實現方式

 更新時間:2019年01月28日 08:39:55   作者:Single_Yam  
這篇文章主要給大家介紹了關于Java定時任務的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

現代的應用程序早已不是以前的那些由簡單的增刪改查拼湊而成的程序了,高復雜性早已是標配,而任務的定時調度與執(zhí)行也是對程序的基本要求了。

很多業(yè)務需求的實現都離不開定時任務,例如,每月一號,移動將清空你上月未用完流量,重置套餐流量,以及備忘錄提醒、鬧鐘等功能。

Java 系統中主要有三種方式來實現定時任務:

  • Timer和TimerTask
  • ScheduledExecutorService
  • 三方框架 Quartz

下面我們一個個來看。

Timer和TimerTask

先看一個小 demo,接著我們再來分析其中原理:

這種方式的定時任務主要用到兩個類,Timer 和 TimerTask。其中,TimerTask 繼承接口 Runnable,抽象的描述一種任務類型,我們只要重寫實現它的 run 方法就可以實現自定義任務。

而 Timer 就是用于定時任務調度的核心類,demo 中我們調用其 schedule 并指定延時 1000 毫秒,所以上述代碼會在一秒鐘后完成打印操作,接著程序結束。

那么,使用上很簡單,兩個步驟即可,但是其中的實現邏輯是怎樣的呢?

Timer 接口

首先,Timer 接口中,這兩個字段是非常核心重要的:

TaskQueue 是一個隊列,內部由動態(tài)數組實現的最小堆結構,換句話說,它是一個優(yōu)先級隊列。而優(yōu)先級參考下一次執(zhí)行時間,越快執(zhí)行的越排在前面,這一點我們回頭再研究。

接著,這個 TimerThread 類其實是 Timer 的一個內部類,它繼承了 Thread 并重寫了其 run 方法,該線程實例將在構建 Timer 實例的時候被啟動。

run 方法內部會循環(huán)的從隊列中取任務,如果沒有就阻塞自己,而當我們成功的向隊列中添加了定時任務,也會嘗試喚醒該線程。

我們也來看一下 Timer 的構造方法:

public Timer(String name) {
 thread.setName(name);
 thread.start();
}

再簡單不過的構造函數了,為內部線程設置線程名,并啟動該線程。

最后,我們著重看一下 Timer 中用于配置一個定時任務進任務隊列的方法。

//在時刻 time 處執(zhí)行任務
schedule(TimerTask task, Date time)

//延時 delay 毫秒后執(zhí)行任務
schedule(TimerTask task, long delay)

//固定延時重復執(zhí)行,firstTime為首次執(zhí)行時間,
//往后沒間隔 period 毫秒執(zhí)行一次
schedule(TimerTask task, Date firstTime, long period)

//固定延時重復執(zhí)行
//首次執(zhí)行時間為當前時間延時 delay 毫秒
schedule(TimerTask task, long delay, long period)

//固定頻率重復執(zhí)行,每過 period 毫秒執(zhí)行一次
scheduleAtFixedRate(TimerTask task, Date firstTime, long period)

//固定頻率重復執(zhí)行
scheduleAtFixedRate(TimerTask task, long delay, long period)

相信有了注釋,這幾個方法的區(qū)別與作用應該不難理解,但是其中有兩個概念需要作一點區(qū)分。

==固定延時== VS ==固定頻率==

固定延時:以任務的上一次 實際 執(zhí)行時間做參考,往后延時 period 毫秒。

固定頻率:任務的往后每一次執(zhí)行時間都在任務提交的那一刻得到了確定,不論你上次任務是否意外延時了,定時定點執(zhí)行下一次任務。

這兩者的區(qū)別還是很大的,希望你能夠理解清楚,接著我們以其中一個方法為例,看看底層實現。

以這個方法為例,其他重載方法的底層調用都是同樣的,我們不去贅述。

這個方法的作用,我們再說一遍。

以當前時間為準,延時 delay 毫秒后第一次執(zhí)行該任務,并且采取固定延時的方式,每隔 period 毫秒再次執(zhí)行該任務。

開頭的兩個異常判斷我們不再贅述,看看 sched 方法:

方法需要傳入三個參數,參數 task 代表的需要執(zhí)行的任務體,TimerTask 我們回頭會詳細介紹,這里你知道它代表了一個任務體即可。

參數 time 描述了該任務下一次執(zhí)行的時刻,計算機底層是以毫秒描述時刻的,所以這里轉換為 long 類型來描述時刻。

參數 period 是固定延時的毫秒數。

整個方法的邏輯我們可以總結概括一下,具體的代碼就不一行行分析了,因為也不難。

  1. 首先使用任務隊列的內置對象鎖,鎖住個隊列。
  2. 接著再去鎖住我們的 task,并修改其內部的一些屬性字段值,nextExecutionTime 指明下一次任務執(zhí)行時間,period 設置固定延時的毫秒數,修改 state 狀態(tài)為計劃中。
  3. 然后將 task 添加到任務隊列,其中 add 方法內部會進行最小堆重構,參考的就是 nextExecutionTime 字段的值,越小優(yōu)先級越高。
  4. 判斷如果自己就是隊列第一個任務,那么將喚醒 Timer 中阻塞了的任務線程。

可能會有人疑問,Timer 如何判斷一個任務是否是重復執(zhí)行的,還是單次執(zhí)行就結束的?

答案在 TimerThread 的 run 方法里,有興趣你可以去研究下,方法體比較多比較長,這里不做分析。

當我們構造 Timer 實例的時候,就會啟動該線程,該線程會在一個死循環(huán)中嘗試從任務隊列上獲取任務,如果成功獲取就執(zhí)行該任務并在執(zhí)行結束之后做一個判斷。

如果 period 值為零,則說明這是一次普通任務,執(zhí)行結束后將從隊列首部移除該任務。

如果 period 為負值,則說明這是一次固定延時的任務,修改它下次執(zhí)行時間 nextExecutionTime 為當前時間減去 period,重構任務隊列。

如果 period 為正數,則說明這是一次固定頻率的任務,修改它下次執(zhí)行時間為 上次執(zhí)行時間加上 period,并重構任務隊列。

其實,我也已經把 TimerThread 的 run 方法里最核心的邏輯也已經介紹了,建議大家親自去研究研究具體代碼的實現,你會對這一塊的邏輯更清晰。

最后,我們看一看這個 Timer 它有哪些劣勢的地方:

  • Timer 的背后只有一個線程,不管你有多少個任務,都只有一個工作線程,效率上必然是要打折扣的。
  • 限于單線程,如果第一個任務邏輯上死循環(huán)了,后續(xù)的任務一個都得不到執(zhí)行。
  • 依然是由于單線程,任一任務拋出異常后,整個 Timer 就會結束,后續(xù)任務全部都無法執(zhí)行。

所以你看,單線程的 Timer 帶來了太多局限性,于是我們看它的替代者。

PS:本來計劃再介紹下 TimerTask 這個抽象任務類的,但是發(fā)現實在沒啥好介紹的,就是增加了兩個字段,一個用于記錄下一次該任務的執(zhí)行時間,一個用于延時毫秒數。你也只需要重寫其 run 方法即可。

ScheduledExecutorService

這個接口相信你一定眼熟,我告訴你在哪見過。

你看,它是我們異步框架中的接口,正好我們今天來介紹他,這樣整個異步框架中所有的接口我們都分析過了。

ScheduledExecutorService中定義的這四個接口方法和 Timer 中對應的方法幾乎一樣,只不過 Timer 的 scheduled 方法需要在外部傳入一個 TimerTask 的抽象任務。

而我們的 ScheduledExecutorService 封裝的更加細致了,隨便你傳 Runnable 或是 Callable,我會在內部給你做一層封裝,封裝一個類似 TimerTask 的抽象任務類(ScheduledFutureTask)。

然后傳入線程池,啟動線程去執(zhí)行該任務,而我們的 ScheduledFutureTask 重寫的 run 方法是這樣的:

如果 periodic 為 true 則說明這是一個需要重復執(zhí)行的任務,否則說明是一個一次性任務。

所以實際執(zhí)行該任務的時候,需要分類,如果是普通的任務就直接調用 run 方法執(zhí)行即可,否則在執(zhí)行結束之后還需要重置下下一次執(zhí)行時間。

整體來說,ScheduledExecutorService 區(qū)別于 Timer 的地方就在于前者依賴了線程池來執(zhí)行任務,而任務本身會判斷是什么類型的任務,需要重復執(zhí)行的在任務執(zhí)行結束后會被重新添加到任務隊列。

而對于后者來說,它只依賴一個線程不停的去獲取隊列首部的任務并嘗試執(zhí)行它,無論是效率上、還是安全性上都比不上前者。

所以,建議使用 ScheduledExecutorService 取代 Timer,當然,通過學習 Timer 會更有助于對 ScheduledExecutorService 的研究。

三方框架 Quartz

除了上述兩種定時任務框架外,Java 生態(tài)圈還存在一種開源的三方框架,他就是 Quartz。

Quartz 是一個功能完善的任務調度框架,支持集群環(huán)境下的任務調度,需要將任務調度狀態(tài)序列化到數據庫。

Quartz 已經是隨著分布式概念的流行,成為企業(yè)級定時任務調度框架中的不二選擇。

Quartz 這個框架的使用及與原理在本篇就不做介紹了,我們會在后續(xù)介紹分布式概念的時候再來介紹它與 SpringCloud 平臺下的整合使用情況。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關文章

  • Java計算黑洞數的方法示例

    Java計算黑洞數的方法示例

    這篇文章主要介紹了Java計算黑洞數的方法,簡單描述了黑洞數的概念及具體計算方法,涉及java數值運算相關操作技巧,需要的朋友可以參考下
    2017-12-12
  • 詳解SpringMVC實現圖片上傳以及該注意的小細節(jié)

    詳解SpringMVC實現圖片上傳以及該注意的小細節(jié)

    本篇文章主要介紹了詳解SpringMVC實現圖片上傳以及該注意的小細節(jié),具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-02-02
  • java實現token無感刷新+處理并發(fā)的后端方案

    java實現token無感刷新+處理并發(fā)的后端方案

    在Web應用中,Token用于身份驗證和會話管理,但當Token過期時,可能會導致用戶在提交表單或進行操作時突然被重定向到登錄頁面,本文就來介紹一下java實現token無感刷新+處理并發(fā)的后端方案,感興趣的可以了解一下
    2024-11-11
  • 使用Springboot實現word在線編輯保存

    使用Springboot實現word在線編輯保存

    PageOffice目前支持的Web編程語言及架構有:Java(JSP、SSH、MVC等),ASP.NET(C#、VB.NET、MVC、Razor等),PHP,ASP,本篇文章就帶你使用Springboot整合PageOffice實現word在線編輯保存
    2021-08-08
  • java獲取網絡圖片上傳到OSS的方法

    java獲取網絡圖片上傳到OSS的方法

    這篇文章主要為大家詳細介紹了java獲取網絡圖片上傳到OSS,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-10-10
  • 關于Feign的覆寫默認配置和Feign的日志

    關于Feign的覆寫默認配置和Feign的日志

    這篇文章主要介紹了關于Feign的覆寫默認配置和Feign的日志方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • IDEA中make directory as的作用及說明

    IDEA中make directory as的作用及說明

    這篇文章主要介紹了IDEA中make directory as的作用及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-09-09
  • java Volatile與Synchronized的區(qū)別

    java Volatile與Synchronized的區(qū)別

    這篇文章主要介紹了java Volatile與Synchronized的區(qū)別,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2020-12-12
  • java之項目運維手冊

    java之項目運維手冊

    這篇文章主要介紹了java之項目運維手冊,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • Java 進制轉換的方法

    Java 進制轉換的方法

    這篇文章介紹了Java 進制轉換的方法,有需要的朋友可以參考一下
    2013-09-09

最新評論

清徐县| 临夏市| 太湖县| 南华县| 汉阴县| 故城县| 黄山市| 凌源市| 嫩江县| 鄂托克旗| 南部县| 视频| 榆树市| 新蔡县| 囊谦县| 彰化县| 黑河市| 泾源县| 龙陵县| 蒙阴县| 图们市| 任丘市| 宣武区| 阳江市| 安福县| 大竹县| 锡林郭勒盟| 泸州市| 永靖县| 上饶市| 儋州市| 宁河县| 湟源县| 章丘市| 辉县市| 芜湖县| 赫章县| 黄梅县| 银川市| 余江县| 长垣县|