JAVA多線程(十九)Java多線程之CachedThreadPool可緩存線程池

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 併發編程的藝術》):

  1. 首先執行 SynchronousQueue.offer(Runnable task) 提交任務到任務隊列。如果當前 maximumPool 中有閒線程正在執行 SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS),那麼主線程執行 offer 操作與空閒線程執行的 poll 操作配對成功,主線程把任務交給空閒線程執行,execute()方法執行完成,否則執行下面的步驟

  2. 當初始 maximumPool 爲空,或者 maximumPool 中沒有空閒線程時,將沒有線程執行 SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS)。這種情況下,步驟 1 將失敗,此時 CachedThreadPool 會創建新線程執行任務,execute 方法執行完成;

    – 以上爲《JAVA多線程(十九)Java多線程之CachedThreadPool可緩存線程池》,如有不當之處請指出,我後續逐步完善更正,大家共同提高。謝謝大家對我的關注。

——厚積薄發(yuanxw)

發佈了125 篇原創文章 · 獲贊 166 · 訪問量 47萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章