ScheduledThreadPoolExecutor類繼承了ThreadPoolExecutor並實現了ScheduledExecutorService接口。主要用於在給定的延遲後執行任務或者定期執行任務。作用類似於java.util包下的Timer類,但是比Timer功能更強大、更靈活,因爲Timer只能控制單個線程延遲或定期執行,而ScheduledThreadPoolExecutor對應的是多個線程的後臺線程。
一、ScheduledThreadPoolExecutor的創建:
可以利用Executors工廠類來創建兩種ScheduledThreadPoolExecutor:ScheduledThreadPoolExecutor和SingleThreadScheduledExecutor.
ScheduledThreadPoolExecutor:適用於若干個(固定)線程延時或者定期執行任務,同時爲了滿足資源管理的需求而需要限制後臺線程數量的場景。
ScheduledExecutorService stp = Executors.newScheduledThreadPool(int threadNums);
ScheduledExecutorService stp = Executors.newScheduledThreadPool(int threadNums, ThreadFactory threadFactory);
SingleThreadScheduledExecutor:適用於需要單個線程延時或者定期的執行任務,同時需要保證各個任務順序執行的應用場景。
ScheduledExecutorService stse = Executors.newSingleThreadScheduledExecutor(int threadNums);
ScheduledExecutorService stp = Executors.newSingleThreadScheduledExecutor(int threadNums, ThreadFactory threadFactory);
二、ScheduledThreadPoolExecutor的實現
通過查看源碼,可以發現ScheduledThreadPoolExecutor的實現主要是通過把任務封裝爲ScheduledFutureTask來實現。ScheduledThreadPoolExecutor通過它的scheduledAtFixedTime()方法或者scheduledWithFixedDelay()方法向阻塞隊列添加一個實現了RunnableScheduledFutureTask接口的ScheduledFutureTask類對象。
ScheduledFutureTask主要包括3個成員變量:
private final long sequenceNumber;
private long time;
private final long period;
sequenceNumber:序列號,用於保存任務添加到阻塞隊列的順序;
time:用於保存該任務將要被執行的具體時間;
period:週期,用於保存任務執行的間隔週期;
此外,ScheduledTreadPoolExecutor的阻塞隊列是用DelayQueue實現的,可以實現元素延時delayTime後才能獲取元素,在ScheduledThreadPoolExecutor中,DelayQueue內部封裝了一個PriorityQueue,來對任務進行排序,首先對time排序,time小的在前,如果time一樣,則sequence小的在前,也就是說如果time一樣,那麼先被提交的任務先執行。
因爲DelayQueue是一個無界的隊列,因此線程池的maximumPoolSize是無效的。ScheduledThreadPoolExecutor的工作流程大致如下:
- 主線程把調用ScheduledFutureTask對象的scheduledAtFixedRate()或者scheduledWithFixedDelay()方法把Runnable或者Callable對象包裝成ScheduledFutureTask對象添加到阻塞隊列中;
- 線程池中的線程1從阻塞隊列中獲取到期的ScheduledFutureTask任務,並執行任務;(到期的意思就是當前時間大於time)
- 執行完任務後把成員變量time改爲下次要執行任務的時間,然後把新的ScheduledFutureTask任務重新放入阻塞隊列中;