線程池介紹

概述

多線程并行處理任務是壓榨 CPU 的最有效方式,而線程在執行完任務后如果直接銷毀,這個是對資源的浪費,于是就有了池化的概念;
創建一個包含多個線程的池,當需要用到線程是是直接使用池中的線程,而不是單獨在創建一個線程,從而避免了線程重復創建和銷毀的開銷,提高了資源的利用率;
線程池是通過生成者消費者模式構建的,當我們使用線程池的 submit 方法提交任務時,就是擔任了生產者的角色來提交任務,當線程池中的線程執行隊列中的任務時就是擔任類消費者的模式消費任務;
在 JDK 中提供了 ThreadPoolExecutor 類用來實現線程池。

線程池參數介紹

首先給出創建線程池類的構造方法:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

可以看到構造方法中入參有7個,接下來分別介紹;

corePoolSize

線程池的核心線程數;所謂核心線程數就是線程池通常情況下維護的最大線程數,而通常情況指的是當 workQueue 未滿,也就是只要任務隊列未滿,線程池中最大線程數就是核心線程數;具體的執行過程是,當線程池中線程數未達到 corePoolSize 時,一個任務被提交后線程池會先創建一個線程去執行該任務,當線程池中線程數達到了 corePoolSize 后,一個任務被提交后會放入到任務隊列中,只要隊列未滿,線程池中最大線程數就是 corePoolSize;

maximumPoolSize

最大線程數;這個就是真正意義上的線程池中所能創建線程的最大值了,只有當任務隊列已滿,有新任務被提交后線程池才會創建新線程來執行任務,這個時候線程池的線程數量會超過 corePoolSize 的大小,當線程池的線程數達到 maximumPoolSize 時,線程池會執行 handler 里的拒絕策略;

keepAliveTime & unit

線程的保留時間和時間單位;這個針對的是非核心線程而言的,因為當隊列滿了之后才會創建非核心線程之外的額外線程來處理任務,但是當任務處理完成隊列又有容量的時候,說明線程池是處在閑置的狀態,而多余的線程就是一種資源的浪費,所以線程池會將多余的線程移除并銷毀,而這個保留時間就是指當線程池處于閑置狀態時,多余的線程在池中最大的保留時間,超過這個時間后,多余的線程就會被銷毀;

threadFactory

線程池中創建線程的工廠;這個其實沒啥好介紹的,就是一個線程池創建的工廠,可以自定義一個線程工廠,給線程設置自定義的名稱等,方便查日志及定位問題;

workQueue

線程池中用來保存提交任務的阻塞隊列;上文中提到線程池是基于生產者消費者模型構建的,因此就需要用到阻塞隊列來存儲對應的任務,生產者把任務提交到隊列,消費者從隊列中獲取任務進行執行;在 JDK 中提供了幾種阻塞隊列;
ArrayBlockingQueue:使用數組實現的阻塞隊列因此構造時必須要傳隊列的大小,因此是一個有界的隊列;
LinkedBlockingQueue:使用鏈表實現的阻塞隊列,如果指定大小則容量以指定大小為準否則取 int 的最大值;
SynchronousQueue:內部只能包含一個元素的同步隊列,能保證兩個線程同步執行;
PriorityBlockingQueue : 使用平衡二叉樹堆實現的優先級隊列無界阻塞隊列,每次都返回優先級最低或最高的元素;

handler

線程池中的拒絕策略;這個拒絕策略其實是一個兜底的方案,因為線程池是有界的,有最大線程數的限制也有最大隊列容量的限制,當超過線程池本身的限制時,我們提交的任務線程池其實是沒有能力再去處理的,這個時候就需要一個兜底的方案去做這件事情,而拒絕策略就是用來做這個的;在 JDK 中為我們提供了幾種拒絕策略,我們也可以去自己實現拒絕策略,下面介紹一下JDK 提供的拒絕策略;
AbortPolicy(默認):丟棄當前任務并拋出 RejectedExecutionException 異常;
DiscardPolicy:丟棄當前任務,不拋出異常;
DiscardOldestPolicy:丟棄隊列中最舊的任務,然后將當前任務加入隊列;
CallerRunsPolicy:使用用調用者的線程繼續執行任務;

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。