並發編程從零開始(十四)-Executors工具類


並發編程從零開始(十四)-Executors工具類

12 Executors工具類

concurrent包提供了Executors工具類,利用它可以創建各種不同類型的線程池

12.1 四種對比

單線程的線程池:

image-20211102170108915

固定數目線程的線程池:

image-20211102171055728

每接收一個請求,就創建一個線程來執行:

image-20211102172234191

單線程具有周期調度功能的線程池:

image-20211102172303690

多線程,有調度功能的線程池:

image-20211102172315063


12.2 最佳實踐

不同類型的線程池,其實都是由前面的幾個關鍵配置參數配置而成的。

在《阿里巴巴Java開發手冊》中,明確禁止使用Executors創建線程池,並要求開發者直接使用ThreadPoolExector或ScheduledThreadPoolExecutor進行創建。這樣做是為了強制開發者明確線程池的運行策略,使其對線程池的每個配置參數皆做到心中有數,以規避因使用不當而造成資源耗盡的風險。


13 ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor實現了按時間調度來執行任務:

1. 延遲執行任務

image-20211102181437787

image-20211102181444236

2. 周期執行任務

image-20211102181510358

image-20211102181516736

區別如下:

AtFixedRate:按固定頻率執行,與任務本身執行時間無關。但有個前提條件,任務執行時間必須小於間隔時間,例如間隔時間是5s,每5s執行一次任務,任務的執行時間必須小於5s。

WithFixedDelay:按固定間隔執行,與任務本身執行時間有關。例如,任務本身執行時間是10s,間隔2s,則下一次開始執行的時間就是12s。


13.1 延遲執行和周期性執行的原理

ScheduledThreadPoolExecutor繼承了ThreadPoolExecutor,這意味着其內部的數據結構和ThreadPoolExecutor是基本一樣的,那它是如何實現延遲執行任務和周期性執行任務的呢?

延遲執行任務依靠的是DelayQueue。DelayQueue是 BlockingQueue的一種,其實現原理是二叉堆。

而周期性執行任務是執行完一個任務之后,再把該任務扔回到任務隊列中,如此就可以對一個任務反復執行。

不過這里並沒有使用DelayQueue,而是在ScheduledThreadPoolExecutor內部又實現了一個特定的DelayQueue

image-20211102183205357

其原理和DelayQueue一樣,但針對任務的取消進行了優化。下面主要講延遲執行和周期性執行的實現過程。


13.2 延遲執行

image-20211102183251134

傳進去的是一個Runnable,外加延遲時間delay。在內部通過decorateTask(...)方法把Runnable包裝成一個ScheduleFutureTask對象,而DelayedWorkQueue中存放的正是這種類型的對象,這種類型的對象一定實現了Delayed接口。

image-20211102183302311

image-20211102183324118

從上面的代碼中可以看出,schedule()方法本身很簡單,就是把提交的Runnable任務加上delay時間,轉換成ScheduledFutureTask對象,放入DelayedWorkerQueue中。任務的執行過程還是復用的ThreadPoolExecutor,延遲的控制是在DelayedWorkerQueue內部完成的。


13.4 執行周期

image-20211102183354946

image-20211102183433106

和schedule(...)方法的框架基本一樣,也是包裝一個ScheduledFutureTask對象,只是在延遲時間參數之外多了一個周期參數,然后放入DelayedWorkerQueue就結束了。

兩個方法的區別在於一個傳入的周期是一個負數,另一個傳入的周期是一個正數,為什么要這樣做呢?

用於生成任務序列號的sequencer,創建ScheduledFutureTask的時候使用:

image-20211102183456120

image-20211102184926446

image-20211102184939941

withFixedDelay和atFixedRate的區別就體現在setNextRunTime里面。

如果是atFixedRate,period>0,下一次開始執行時間等於上一次開始執行時間+period;

如果是withFixedDelay,period < 0,下一次開始執行時間等於triggerTime(-p),為now+(-period),now即上一次執行的結束時間。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM