定時週期延時執行緒池:ScheduledThreadPoolExecutor
轉載地址:
https://www.jianshu.com/p/c41e942bcd64
轉載地址:
https://www.jianshu.com/p/502f9952c09b
一.ThreadPoolExecutor概述
執行緒池解決了兩個不同問題:
1.效能提升:他們通常在執行大量非同步任務時,減少了執行緒的建立開銷,使效能得到了提升。
2.統計資訊:可以統計完成的任務數量
執行緒池的構造方法有四種:
其中最全的一個是
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
}
1.corepoolsize和maximumpoolsize
其中corepoolsize是執行緒池核心執行緒數
具體的:當接收到一個任務時,當前的執行緒數少於corepoolsize的大小,無論是否空閒執行緒都會啟動一個新的執行緒來執行任務。
如果有多與corepoolsize但小於maximumpoolsize 的執行緒正在執行,則當前佇列滿時才會建立一個新的執行緒執行任務,
2.prestartCoreThread 核心執行緒預啟動
prestartCoreThread() 創一個空閒任務執行緒等待任務的到達
prestartAllCoreThreads() 建立核心執行緒池數量的空閒任務執行緒等待任務的到達
3.ThreadFactory 執行緒工廠
4.Keep-alive times 執行緒存活時間
如果當前持有的執行緒多於corepoolsize多餘的執行緒在空餘時間超過Keep-alive times後就會被終止。
注:預設情況下,keep-alive策略僅適用於存在超過corePoolSize執行緒的情況。 但是,只要keepAliveTime值不為零,方法allowCoreThreadTimeOut(boolean)也可用於將此超時策略應用於核心執行緒。
5.Queuing 佇列
BlockingQueu用於存放提交的任務,佇列的實際容量與執行緒池大小相關聯。
主要有三種佇列策略:
⑴Direct handoffs 直接握手佇列
Direct handoffs 的一個很好的預設選擇是 SynchronousQueue,它將任務交給執行緒而不需要保留。這裡,如果沒有執行緒立即可用來執行它,那麼排隊任務的嘗試將失敗,因此將構建新的執行緒。
此策略在處理可能具有內部依賴關係的請求集時避免鎖定。Direct handoffs 通常需要無限制的maximumPoolSizes來避免拒絕新提交的任務。 但得注意,當任務持續以平均提交速度大餘平均處理速度時,會導致執行緒數量會無限增長問題。
⑵Unbounded queues 無界佇列
當所有corePoolSize執行緒繁忙時,使用無界佇列(例如,沒有預定義容量的LinkedBlockingQueue)將導致新任務在佇列中等待,從而導致maximumPoolSize的值沒有任何作用。當每個任務互不影響,完全獨立於其他任務時,這可能是合適的; 例如,在網頁伺服器中, 這種佇列方式可以用於平滑瞬時大量請求。但得注意,當任務持續以平均提交速度大餘平均處理速度時,會導致佇列無限增長問題。
⑶Bounded queues 有界佇列
一個有界的佇列(例如,一個ArrayBlockingQueue)和有限的maximumPoolSizes配置有助於防止資源耗盡,但是難以控制。佇列大小和maximumPoolSizes需要 相互權衡:
使用大佇列和較小的maximumPoolSizes可以最大限度地減少CPU使用率,作業系統資源和上下文切換開銷,但會導致人為的低吞吐量。如果任務經常被阻塞(比如I/O限制),那麼系統可以排程比我們允許的更多的執行緒。
使用小佇列通常需要較大的maximumPoolSizes,這會使CPU更繁忙,但可能會遇到不可接受的排程開銷,這也會降低吞吐量。
6.Rejected tasks 拒絕任務
拒絕任務有兩種情況:1. 執行緒池已經被關閉;2. 任務佇列已滿且maximumPoolSizes已滿;
無論哪種情況,都會呼叫RejectedExecutionHandler的rejectedExecution方法。
二.ScheduledThreadPoolExecutor
構造方法:
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
};
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory);
};
public ScheduledThreadPoolExecutor(int corePoolSize,
RejectedExecutionHandler handler) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), handler);
};
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory, handler);
}
特有方法:
ScheduledThreadPoolExecutor實現了ScheduledExecutorService介面,該介面定義了可延時執行非同步任務和可週期執行非同步任務的特有功能,相應的方法分別為:
//達到給定的延時時間後,執行任務。這裡傳入的是實現Runnable介面的任務,
//因此通過ScheduledFuture.get()獲取結果為null
public ScheduledFuture<?> schedule(Runnable command,
long delay, TimeUnit unit);
//達到給定的延時時間後,執行任務。這裡傳入的是實現Callable介面的任務,
//因此,返回的是任務的最終計算結果
public <V> ScheduledFuture<V> schedule(Callable<V> callable,
long delay, TimeUnit unit);
//是以上一個任務開始的時間計時,period時間過去後,
//檢測上一個任務是否執行完畢,如果上一個任務執行完畢,
//則當前任務立即執行,如果上一個任務沒有執行完畢,則需要等上一個任務執行完畢後立即執行
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit);
//當達到延時時間initialDelay後,任務開始執行。上一個任務執行結束後到下一次
//任務執行,中間延時時間間隔為delay。以這種方式,週期性執行任務。
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit);