JAVA多線程(二十)Java多線程之FixedThreadPool可重用固定線程數的線程池

1.JAVA多線程(二十)Java多線程之FixedThreadPool可重用固定線程數的線程池

1.1 可重用固定線程數的線程池FixedThreadPool

   可重用固定線程數的線程池FixedThreadPool特點是:只有核心線程,不會被回收、線程數量固定、任務隊列無大小限制(超出的線程任務會在隊列中等待),通過源代碼查看FixedThreadPool實現:

    /**
     * Creates a thread pool that reuses a fixed number of threads
     * operating off a shared unbounded queue.  At any point, at most
     * {@code nThreads} threads will be active processing tasks.
     * If additional tasks are submitted when all threads are active,
     * they will wait in the queue until a thread is available.
     * If any thread terminates due to a failure during execution
     * prior to shutdown, a new one will take its place if needed to
     * execute subsequent tasks.  The threads in the pool will exist
     * until it is explicitly {@link ExecutorService#shutdown shutdown}.
     *
     * @param nThreads the number of threads in the pool
     * @return the newly created thread pool
     * @throws IllegalArgumentException if {@code nThreads <= 0}
     */
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

    /**
     * Creates a thread pool that reuses a fixed number of threads
     * operating off a shared unbounded queue, using the provided
     * ThreadFactory to create new threads when needed.  At any point,
     * at most {@code nThreads} threads will be active processing
     * tasks.  If additional tasks are submitted when all threads are
     * active, they will wait in the queue until a thread is
     * available.  If any thread terminates due to a failure during
     * execution prior to shutdown, a new one will take its place if
     * needed to execute subsequent tasks.  The threads in the pool will
     * exist until it is explicitly {@link ExecutorService#shutdown
     * shutdown}.
     *
     * @param nThreads the number of threads in the pool
     * @param threadFactory the factory to use when creating new threads
     * @return the newly created thread pool
     * @throws NullPointerException if threadFactory is null
     * @throws IllegalArgumentException if {@code nThreads <= 0}
     */
    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }

    /**
     * Creates a {@code LinkedBlockingQueue} with a capacity of
     * {@link Integer#MAX_VALUE}.
     */
    public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }

在FixedThreadPool實現中:

  • corePoolSize && maximumPoolSize,核心線程數和允許最大的線程數一致,可以指定無限大,在資源有限的情況下容易引起OOM異常。
  • keepAliveTime => keepAliveTime爲0,意味着多餘的空閒線程會被立即終止。
  • workQueue => 採用無界隊列LinkedBlockingQueue作爲線程池的工作隊列(隊列的容量爲Integer.MAX_VALUE),會在循環中反覆從LinkedBlockingQueue獲取任務來執行。

1.2 FixedThreadPool使用樣例

FixedThreadPool線程池使用LinkedBlockingQueue作爲線程池的工作隊列會對線程池帶來如下影響:

  • 當線程池中的線程數達到corePoolSize核心線程數後,新任務將在無界隊列中等待,因此線程池中的線程數不會超過corePoolSize核心線程數。
  • 使用無界隊列,運行中的FixedThreadPool不會拒絕任務,(未執行方法shutdown()或shutdownNow(),不會調用RejectedExecutionHandler.rejectedExecution方法),在任務比較多的時候會導致 OOM(內存溢出)。
package com.yuanxw.chapter20;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class FixedThreadPoolExample {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService;
        System.out.println("獲得活動的線程評估數:" + threadPoolExecutor.getActiveCount());

        for (int i = 0; i < 10; 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());
        // corePoolSize 等於 maximumPoolSize,因此應用程序不會結束,需要調用executorService.shutdown()方法,關閉線程池。
        executorService.shutdown();
    }
}

執行結果:

獲得活動的線程評估數:0
線程【pool-1-thread-2】正在工作>>>>
線程【pool-1-thread-3】正在工作>>>>
獲得活動的線程評估數:5
線程【pool-1-thread-1】正在工作>>>>
獲得活動的線程評估數:4
線程【pool-1-thread-5】正在工作>>>>
獲得活動的線程評估數:5
獲得活動的線程評估數:5
線程【pool-1-thread-4】正在工作>>>>
獲得活動的線程評估數:5
線程【pool-1-thread-4】正在工作>>>>
線程【pool-1-thread-3】正在工作>>>>
線程【pool-1-thread-2】正在工作>>>>
線程【pool-1-thread-5】正在工作>>>>
獲得活動的線程評估數:5
線程【pool-1-thread-1】正在工作>>>>
獲得活動的線程評估數:5
獲得活動的線程評估數:5
獲得活動的線程評估數:5
獲得活動的線程評估數:4
獲得活動的線程評估數:0

在這裏插入圖片描述
FixedThreadPool 的 execute()方法的執行示意圖(該圖片來源:《Java 併發編程的藝術》):

  1. 如果當前運行的線程數小於 corePoolSize, 如果再來新任務的話,就創建新的線程來執行任務;
  2. 當前運行的線程數等於 corePoolSize 後, 如果再來新任務的話,會將任務加入 LinkedBlockingQueue;
  3. 線程池中的線程執行完當前的任務後,會在循環中反覆從 LinkedBlockingQueue 中獲取任務來執行;

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

——厚積薄發(yuanxw)

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