1.JAVA多線程(十九)Java多線程之CachedThreadPool可緩存線程池
1.1 可緩存線程池CachedThreadPool
可緩存線程池CachedThreadPool是一個根據需要創建新線程的線程池。
通過源代碼查看CachedThreadPool實現:
/**
* Creates a thread pool that creates new threads as needed, but
* will reuse previously constructed threads when they are
* available. These pools will typically improve the performance
* of programs that execute many short-lived asynchronous tasks.
* Calls to {@code execute} will reuse previously constructed
* threads if available. If no existing thread is available, a new
* thread will be created and added to the pool. Threads that have
* not been used for sixty seconds are terminated and removed from
* the cache. Thus, a pool that remains idle for long enough will
* not consume any resources. Note that pools with similar
* properties but different details (for example, timeout parameters)
* may be created using {@link ThreadPoolExecutor} constructors.
*
* @return the newly created thread pool
*/
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
/**
* Creates a thread pool that creates new threads as needed, but
* will reuse previously constructed threads when they are
* available, and uses the provided
* ThreadFactory to create new threads when needed.
* @param threadFactory the factory to use when creating new threads
* @return the newly created thread pool
* @throws NullPointerException if threadFactory is null
*/
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
在CachedThreadPool實現中:
- corePoolSize => 0,核心線程池的數量爲:0
- maximumPoolSize => Integer.MAX_VALUE,線程池最大數量爲Integer.MAX_VALUE,可以認爲可以無限創建線程。在資源有限的情況下容易引起OOM異常。
- keepAliveTime => keepAliveTime爲60少,意味着線程空閒時間超過60S就會被殺死;
- workQueue => 採用SynchronousQueue裝等待的任務,這個阻塞隊列沒有存儲空間,這意味着只要有請求到來,就必須要找到一條工作線程處理他,如果當前沒有空閒的線程,那麼就會再創建一條新的線程。
1.2 CachedThreadPool使用樣例
CachedThreadPool線程池特點:
- 工作線程的創建數量幾乎沒有限制(其實也有限制的,數目爲Interger. MAX_VALUE), 這樣可靈活的往線程池中添加線程。
- keepAliveTime時長爲60秒,超過60秒的空閒線程就會被回收,當線程池都處於閒置狀態時,線程池中的線程都會因爲超時而被回收,所以幾乎不會佔用什麼系統資源。任務隊列採用的是SynchronousQueue,這個隊列是無法插入任務的,一有任務立即執行,所以CachedThreadPool比較適合任務量大但耗時少的任務。
package com.yuanxw.chapter19;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class CachedThreadPoolExample {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService;
System.out.println("獲得活動的線程評估數:" + threadPoolExecutor.getActiveCount());
executorService.execute(()->System.out.println(String.format("線程【%s】正在工作......", Thread.currentThread().getName())));
System.out.println("獲得活動的線程評估數:" + threadPoolExecutor.getActiveCount());
for (int i = 0; i < 20; i++) {
executorService.execute(()->{
try {
TimeUnit.SECONDS.sleep(1);
System.out.println(String.format("線程【%s】正在工作>>>>", Thread.currentThread().getName()));
System.out.println("獲得活動的線程評估數:" + threadPoolExecutor.getActiveCount());
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
TimeUnit.SECONDS.sleep(5);
System.out.println("獲得活動的線程評估數:" + threadPoolExecutor.getActiveCount());
}
}
執行結果:
獲得活動的線程評估數:0
獲得活動的線程評估數:1
線程【pool-1-thread-1】正在工作......
線程【pool-1-thread-3】正在工作>>>>
線程【pool-1-thread-7】正在工作>>>>
線程【pool-1-thread-5】正在工作>>>>
獲得活動的線程評估數:20
線程【pool-1-thread-4】正在工作>>>>
線程【pool-1-thread-6】正在工作>>>>
線程【pool-1-thread-2】正在工作>>>>
獲得活動的線程評估數:19
獲得活動的線程評估數:19
獲得活動的線程評估數:20
獲得活動的線程評估數:20
獲得活動的線程評估數:19
線程【pool-1-thread-19】正在工作>>>>
線程【pool-1-thread-15】正在工作>>>>
線程【pool-1-thread-21】正在工作>>>>
線程【pool-1-thread-16】正在工作>>>>
線程【pool-1-thread-20】正在工作>>>>
線程【pool-1-thread-14】正在工作>>>>
獲得活動的線程評估數:14
線程【pool-1-thread-8】正在工作>>>>
獲得活動的線程評估數:14
獲得活動的線程評估數:14
線程【pool-1-thread-11】正在工作>>>>
線程【pool-1-thread-12】正在工作>>>>
線程【pool-1-thread-18】正在工作>>>>
獲得活動的線程評估數:14
獲得活動的線程評估數:11
獲得活動的線程評估數:11
獲得活動的線程評估數:11
獲得活動的線程評估數:13
線程【pool-1-thread-9】正在工作>>>>
線程【pool-1-thread-13】正在工作>>>>
獲得活動的線程評估數:14
線程【pool-1-thread-10】正在工作>>>>
獲得活動的線程評估數:14
線程【pool-1-thread-17】正在工作>>>>
獲得活動的線程評估數:5
獲得活動的線程評估數:6
獲得活動的線程評估數:6
獲得活動的線程評估數:4
獲得活動的線程評估數:0
CachedThreadPool 的 execute()方法的執行示意圖(該圖片來源:《Java 併發編程的藝術》):
-
首先執行 SynchronousQueue.offer(Runnable task) 提交任務到任務隊列。如果當前 maximumPool 中有閒線程正在執行 SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS),那麼主線程執行 offer 操作與空閒線程執行的 poll 操作配對成功,主線程把任務交給空閒線程執行,execute()方法執行完成,否則執行下面的步驟
-
當初始 maximumPool 爲空,或者 maximumPool 中沒有空閒線程時,將沒有線程執行 SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS)。這種情況下,步驟 1 將失敗,此時 CachedThreadPool 會創建新線程執行任務,execute 方法執行完成;
– 以上爲《JAVA多線程(十九)Java多線程之CachedThreadPool可緩存線程池》,如有不當之處請指出,我後續逐步完善更正,大家共同提高。謝謝大家對我的關注。
——厚積薄發(yuanxw)