java筆記-ThreadPoolExecutor

為什么用線程池

有時候,系統(tǒng)需要處理非常多的執(zhí)行時間很短的請求,如果每一個請求都開啟一個新線程的話,系統(tǒng)就要不斷的進(jìn)行線程的創(chuàng)建和銷毀,有時花在創(chuàng)建和銷毀線程上的時間會比線程真正執(zhí)行的時間還長。而且當(dāng)線程數(shù)量太多時,系統(tǒng)不一定能受得了。

使用線程池主要為了解決一下幾個問題:

  • 通過重用線程池中的線程,來減少每個線程創(chuàng)建和銷毀的性能開銷。
  • 對線程進(jìn)行一些維護(hù)和管理,比如定時開始,周期執(zhí)行,并發(fā)數(shù)控制等等。

Executor

注意:不同于Executors(類)
Executor是一個接口,跟線程池有關(guān)的基本都要跟他打交道。下面是常用的ThreadPoolExecutor的關(guān)系。

線程池規(guī)則驗證

下面都假設(shè)任務(wù)隊列沒有大小限制
  • 如果線程數(shù)量<=核心線程數(shù)量,那么直接啟動一個核心線程來執(zhí)行任務(wù),不會放入隊列中。
  • 如果線程數(shù)量>核心線程數(shù),但<=最大線程數(shù),并且任務(wù)隊列是LinkedBlockingDeque的時候,超過核心線程數(shù)量的任務(wù)會放在任務(wù)隊列中排隊。
  • 如果線程數(shù)量>核心線程數(shù),但<=最大線程數(shù),并且任務(wù)隊列是SynchronousQueue的時候,線程池會創(chuàng)建新線程執(zhí)行任務(wù),這些任務(wù)也不會被放在任務(wù)隊列中。這些線程屬于非核心線程,在任務(wù)完成后,閑置時間達(dá)到了超時時間就會被清除。
  • 如果線程數(shù)量>核心線程數(shù),并且>最大線程數(shù),當(dāng)任務(wù)隊列是LinkedBlockingDeque,會將超過核心線程的任務(wù)放在任務(wù)隊列中排隊。也就是當(dāng)任務(wù)隊列是LinkedBlockingDeque并且沒有大小限制時,線程池的最大線程數(shù)設(shè)置是無效的,他的線程數(shù)最多不會超過核心線程數(shù)。
  • 如果線程數(shù)量>核心線程數(shù),并且>最大線程數(shù),當(dāng)任務(wù)隊列是SynchronousQueue的時候,會因為線程池拒絕添加任務(wù)而拋出異常。
任務(wù)隊列大小有限時
  • 當(dāng)LinkedBlockingDeque塞滿時,新增的任務(wù)會直接創(chuàng)建新線程來執(zhí)行,當(dāng)創(chuàng)建的線程數(shù)量超過最大線程數(shù)量時會拋異常。
  • SynchronousQueue沒有數(shù)量限制。因為他根本不保持這些任務(wù),而是直接交給線程池去執(zhí)行。當(dāng)任務(wù)數(shù)量超過最大線程數(shù)時會直接拋異常。

圖:

image.png

代碼驗證

所有任務(wù)

        /**
         * 所有的任務(wù)
         */
        Runnable runnable = new Runnable() {
            public void run() {
                try {
                    Thread.sleep(2000);
                    System.out.println(Thread.currentThread().getName() + "is runing....");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

驗證示例

ThreadPoolExecutor executor = new ThreadPoolExecutor(6, 10, 5, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
executor.execute(runnable);
        executor.execute(runnable);
        executor.execute(runnable);

        System.out.println("---先開三個---");
        System.out.println("核心線程數(shù):" + executor.getCorePoolSize());
        System.out.println("線程池數(shù):" + executor.getPoolSize());
        System.out.println("隊列任務(wù)數(shù)" + executor.getQueue().size());

        executor.execute(runnable);
        executor.execute(runnable);
        executor.execute(runnable);

        System.out.println("---再開三個---");
        System.out.println("核心線程數(shù):" + executor.getCorePoolSize());
        System.out.println("線程池數(shù):" + executor.getPoolSize());
        System.out.println("隊列任務(wù)數(shù)" + executor.getQueue().size());

        Thread.sleep(8000);

        System.out.println("---8秒之后再來三個---");
        System.out.println("核心線程數(shù):" + executor.getCorePoolSize());
        System.out.println("線程池數(shù):" + executor.getPoolSize());
        System.out.println("隊列任務(wù)數(shù)" + executor.getQueue().size());
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容