【線程池】線程池的初始配置詳解


創建一個線程池

首先我們看一個創建線程池的例子

執行類

public class ThreadInit {

    /**
     * corePoolSize - 要保留在池中的線程數,即使它們處於空閑狀態,除非設置了allowCoreThreadTimeOut
     * maximumPoolSize - maximumPoolSize的最大線程數
     * keepAliveTime - 當線程數大於核心數時,這是多余空閑線程在終止前等待新任務的最長時間。
     * unit - keepAliveTime參數的時間單位
     * workQueue - 用於在執行任務之前保存任務的隊列。 這個隊列將只保存execute方法提交的Runnable任務。
     * threadFactory - 執行程序創建新線程時使用的工廠
     * handler - 由於達到線程邊界和隊列容量而阻塞執行時使用的處理程序
     * @param args
     */
    public static void main(String[] args) {
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(10);
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1,5,10,TimeUnit.SECONDS,workQueue,new TestThreadFactory(),new MyRejectPolicy());

        for (int i = 0; i < 20; i++) {
            threadPoolExecutor.execute(()->{
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+":執行了");
            });
        }
        threadPoolExecutor.shutdown();
    }
}

拒絕策略類

public class MyRejectPolicy implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.out.println("被拒絕了");
    }
}

線程工程類

public class TestThreadFactory implements ThreadFactory {

    private static AtomicInteger atomicInteger = new AtomicInteger();

    @Override
    public Thread newThread(Runnable r) {
        atomicInteger.addAndGet(1);
        return new Thread(r,"自定義名字-"+atomicInteger.get());
    }
}

參數講解

仔細看完上面這個創建線程池的例子后,就會發現,創建一個線程池,有六個可以配置的參數,這六個參數分別是image.png
首先我們先按順序來講解一下這六個參數的各個含義

corePoolSize

核心線程數是線程池會一直保持活躍的線程數,比如我們核心線程數設置為5個線程,那么當線程任務進入到線程池中會始終保持有五個線程的空位使用。

maximumPoolSize

最大線程數與核心線程數還不太一樣,最大線程數是線程池再判斷線程隊列是否滿了,如果滿了則會在核心線程數的基礎上去創建新的線程,直到線程數達到了最大線程數之后變不會在創建。
這里有很多人都會有一個誤區,把核心線程數理解為最小活躍線程,以為當進入到線程池后,如果超過核心線程數的任務會直接去創建線程執行,直到線程數滿了之后然后在把線程存放到線程池的隊列中。其實這種理解是錯誤的,在Java的線程池中,線程池會先去判斷線程隊列有沒有滿,如果滿了,才會在核心線程數上去創建線程。
例如我們上面那個創建線程的例子來看,核心線程數為1個,最大線程數為5個,隊列最大可以存放10個。當客戶端開始執行20個線程的同時,核心線程會占去一個,之后的線程會先存放到線程池的隊列中,此時在隊列中存放了10個后發現還有9個線程需要被放入到線程池中,這是線程池就會把核心線程數擴大到最大線程數5個。
可以參考下這個張圖片
image.png

keepAliveTime

空閑線程的存活時間代表着,如果當我們例子中的線程池在線程數到達最大值的情況下,線程池里面的任務都執行完了,這個時候除了1個核心線程,剩下的4個線程就會保持我們設置的keepAliveTime時間來等待,如果設置10秒后發現還是沒有線程進來,這個時候這4個空閑的線程就會慢慢的關閉掉,直到下次再有線程過來,等到線程隊列滿了之后才會去創建這些線程。

workQueue

workQueue就是我們的線程隊列,例如我們現在設置的隊列BlockingQueue,他是屬於阻塞隊列,並且有最大值。這個設置需要看具體使用場景來設置,例如我們不想丟棄任何一個線程策略,就可以設置Queue,這時他就可以沒有限制的去存放你的線程任務。

threadFactory

線程工廠就比較有意思了,他可以做很多的時候,例如上面的例子中,線程工廠做了一個線程名稱的自定義,因為在業務場景中,線程池中自帶默認的創建線程工廠可能不太符合我們業務需求,例如自定義線程名字,線程計數等等。這種自定義的東西就可以以自己需求來判斷如何改造自己線程創建的方式。

handler

這個的作用是基於線程被拒絕后使用的,比如線程被拒絕后,我們想要知道被拒絕的線程有多少個,或者線程被拒絕后如何去打印被拒絕線程的日志。

總結

通過上面的參數詳解后,我們可以得出線程池的幾個特點和注意事項

  • 線程池希望保持較少的線程數,只有在負載變大的時候才會去擴線程。
  • 線程池只有在任務隊列填滿時才創建多於 corePoolSize 的線程,如果使用的是無界隊列(例如 LinkedBlockingQueue),那么由於隊列不會滿,所以線程數不會超過 corePoolSize。
  • 通過設置 corePoolSize 和 maximumPoolSize 為相同的值,就可以創建固定大小的線程池。
  • 通過設置 maximumPoolSize 為很高的值,例如 Integer.MAX_VALUE,就可以允許線程池創建任意多的線程。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM