中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

定時任務ScheduledExecutorService實現是怎樣的

發布時間:2021-11-15 15:46:17 來源:億速云 閱讀:172 作者:柒染 欄目:大數據

這篇文章將為大家詳細講解有關定時任務ScheduledExecutorService實現是怎樣的,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

現在項目中基本不會自己定義一個ScheduledExecutorService來執行定時任務。都是用第三方框架比如xxl-job之類的,不過了解最基本的定時任務原理還是很有必要的。

ScheduledExecutorService簡單示例

我們先來看最簡單的使用,代碼如下圖:

 定時任務ScheduledExecutorService實現是怎樣的

ScheduledThreadPoolExecutor是ScheduledExecutorService的實現,能做一些基本的定時任務功能。

比如上圖的例子,可以延遲3秒后每隔5秒執行任務。實現起來比較簡單。

基礎源碼分析

首先ScheduledThreadPoolExecutor繼承了ThreadPoolExecutor并實現了ScheduledExecutorService,所以它擁有線程池的功能

然后我們看它的構造方法,它有幾個構造方法,我們以上面示例的為例,方法中只有一行代碼如下:

super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());

調用了父類的構造方法,也就是線程池的構造方法,它自身并沒有實現任務事情,除了new了一個DelayedWorkQueue()給父類,這個是給線程池存放任務隊列的。

提交任務方法源碼

ScheduledThreadPoolExecutor提供了幾個執行定時任務的方法,不過我們還是分析上面用到的scheduleAtFixedRate方法,查看源碼如下圖:

 定時任務ScheduledExecutorService實現是怎樣的

這個方法一共就三步:

首先初始化ScheduledFutureTask,它繼承了FutureTask,擴展了一些定時任務需要的屬性,比如下次執行時間、每次任務執行間隔。

然后調用decorateTask方法裝飾任務,目前沒有做任務事情,我們可以自定義實現一些功能。

最后調用delayedExecute方法,從上圖可以看到這個方法主要流程也簡單,首先是把任務放到線程池的隊列中,然后調用ensurePrestart方法,ensurePrestart方法是線程池的方法,作用是根據線程池線程數調用addWorker方法創建線程,addWorker方法就不多說了,不清楚的同學可以看我前面幾篇的《三分鐘弄懂線程池執行過程》。 

提交定時任務的方法還是很簡單的,包裝一個任務(用于保存定時任務需要的信息),然后提交到線程池的隊列中。 

但是有一個問題是,任務提交到線程池了,我們知道線程池能夠執行任務,但是都是執行一次啊,不會像定時任務那樣執行任務的!那它到底是怎么實現定時任務功能的呢? 

實現定時任務關鍵第一步

從之前文章分析線程池中最終執行的是提交的任務那個對象的run方法,所以ScheduledFutureTask對run方法有特殊的實現,跟進源碼發現run方法正常的流程就兩步:

調用ScheduledFutureTask.super.runAndReset()也就是調用了父類的FutureTask的runAndReset()方法,這個方法沒有什么在上上篇文章有講,就是調用內部的Callable的run,保存結果;

在上一個執行完成也就是任務完成后,調用了setNextRunTime();reExecutePeriodic(outerTask);兩步代碼,第一步是計算下次任務執行時間,第二個是把任務放到隊列中; 

run方法執行了具體的方法,在任務執行成功后重新計算了任務下次執行的時間,并再次把任務加載到了隊列中,重復執行。 

但是到目前為止也只是實現了規定了在什么時候執行與重復執行,那么到底是如何實現在具體的時間執行呢?

延遲隊列實現定時執行

通過還是沒有發現如何實現定時執行的,沒辦法只能繼續跟進代碼,最后跟到線程池的runWorker方法,在獲取Worker的firstTask方法來執行,想起剛剛在調用ensurePrestart方法中調用addWorker方法傳遞的firstTask都是null,也就是說Worker執行的任務都是從隊列中拉取的任務,他們都沒有自己的firstTask

也就想起了在初始化方法給線程池傳遞的隊列是new DelayedWorkQueue();所以應該基本找到問題了,我們來看隊列的take方法:

 定時任務ScheduledExecutorService實現是怎樣的

從源碼可以看到是根據隊列中第一個元素,然后利用ScheduledFutureTask的getDelay方法來判斷是否返回任務或者阻塞,getDelay是根據屬性time(前面提到的下次任務執行時間)減去當前時間。

那么如果第一個任務進來判斷是10秒后執行,第二個任務進來判斷是5秒后執行,那么第二個任務是不是等第一個任務執行完才能執行呢?

很明顯不能這么實現,這里就要看DelayedWorkQueue的add方法了,它并沒有實現add方法,不過add方法調用的offer,DelayedWorkQueue實現了offer方法。

offer方法也簡單,就是把任務加到queue數組中,如果數組為null則直接加進去,并喚醒take哪里的線程,如果不為null則比較數組中任務的time,越近的越在前面,如果新加進來的任務被設置到了數組的第一個,則喚醒take那里阻塞的線程。

ScheduledExecutorService繼承線程池,也是把任務提交給線程池執行,只不過它的任務類進行擴展。

任務類ScheduledFutureTask繼承FutureTask并擴展了一些屬性來記錄任務下次執行時間和每次執行間隔。同時重寫了run方法重新計算任務下次執行時間,并把任務放到線程池隊列中。

ScheduledExecutorService自定義了阻塞隊列DelayedWorkQueue給線程池使用,它可以根據ScheduledFutureTask的下次執行時間來阻塞take方法,并且新進來的ScheduledFutureTask會根據這個時間來進行排序,最小的最前面。

總結起來就是通過線程池來執行任務,ScheduledFutureTask記錄任務定時信息,DelayedWorkQueue來排序任務定時執行。 

關于定時任務ScheduledExecutorService實現是怎樣的就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

镇平县| 金塔县| 桓台县| 宕昌县| 久治县| 曲松县| 永新县| 平谷区| 会泽县| 东平县| 板桥市| 江津市| 宁波市| 台江县| 定远县| 西乡县| 竹山县| 崇信县| 庆安县| 鹤山市| 子长县| 桃园县| 乐清市| 盐城市| 岱山县| 开封县| 萍乡市| 淮滨县| 崇明县| 鸡东县| 岫岩| 犍为县| 怀化市| 桐柏县| 肥乡县| 赤城县| 晋宁县| 金山区| 南江县| 历史| 巫溪县|