java四種線程池的使用


參考:https://blog.csdn.net/w05980598/article/details/79425071

參考:https://blog.csdn.net/achuo/article/details/80623893

 

一、四種線程池 

Java通過Executors提供四種線程池,分別為: 

1、newSingleThreadExecutor 

創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。

2、newFixedThreadPool 

創建一個定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待。

3、newScheduledThreadPool 

創建一個可定期或者延時執行任務的定長線程池,支持定時及周期性任務執行。 

4、newCachedThreadPoo 

創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。 

 

二、使用場景詳解

newCachedThreadPool:

  • 底層:返回ThreadPoolExecutor實例,corePoolSize為0;maximumPoolSize為Integer.MAX_VALUE;keepAliveTime為60L;unit為TimeUnit.SECONDS;workQueue為SynchronousQueue(同步隊列)
  • 通俗:當有新任務到來,則插入到SynchronousQueue中,由於SynchronousQueue是同步隊列,因此會在池中尋找可用線程來執行,若有可以線程則執行,若沒有可用線程則創建一個線程來執行該任務;若池中線程空閑時間超過指定大小,則該線程會被銷毀。
  • 適用:執行很多短期異步的小程序或者負載較輕的服務器
  • /**
         * 1.創建一個可緩存的線程池。如果線程池的大小超過了處理任務所需要的線程,那么就會回收部分空閑(60秒不執行任務)的線程<br>
         * 2.當任務數增加時,此線程池又可以智能的添加新線程來處理任務<br>
         * 3.此線程池不會對線程池大小做限制,線程池大小完全依賴於操作系統(或者說JVM)能夠創建的最大線程大小<br>
         * 
         */
        public static void cacheThreadPool() {
            ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
            for (int i = 1; i <= 10; i++) {
                final int ii = i;
                try {
                    Thread.sleep(ii * 1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
                cachedThreadPool.execute(()->out.println("線程名稱:" + Thread.currentThread().getName() + ",執行" + ii));
            }
    
        }
    -----output------
    線程名稱:pool-1-thread-1,執行1
    線程名稱:pool-1-thread-1,執行2
    線程名稱:pool-1-thread-1,執行3
    線程名稱:pool-1-thread-1,執行4
    線程名稱:pool-1-thread-1,執行5
    線程名稱:pool-1-thread-1,執行6
    線程名稱:pool-1-thread-1,執行7
    線程名稱:pool-1-thread-1,執行8
    線程名稱:pool-1-thread-1,執行9
    線程名稱:pool-1-thread-1,執行10

     

newFixedThreadPool:

  • 底層:返回ThreadPoolExecutor實例,接收參數為所設定線程數量nThread,corePoolSize為nThread,maximumPoolSize為nThread;keepAliveTime為0L(不限時);unit為:TimeUnit.MILLISECONDS;WorkQueue為:new LinkedBlockingQueue<Runnable>() 無界阻塞隊列
  • 通俗:創建可容納固定數量線程的池子,每隔線程的存活時間是無限的,當池子滿了就不在添加線程了;如果池中的所有線程均在繁忙狀態,對於新任務會進入阻塞隊列中(無界的阻塞隊列)
  • 適用:執行長期的任務,性能好很多
  •    /**
         * 1.創建固定大小的線程池。每次提交一個任務就創建一個線程,直到線程達到線程池的最大大小<br>
         * 2.線程池的大小一旦達到最大值就會保持不變,如果某個線程因為執行異常而結束,那么線程池會補充一個新線程<br>
         * 3.因為線程池大小為3,每個任務輸出index后sleep 2秒,所以每兩秒打印3個數字,和線程名稱<br>
         */
        public static void fixTheadPoolTest() {
            ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
            for (int i = 0; i < 10; i++) {
                final int ii = i;
                fixedThreadPool.execute(() -> {
                    out.println("線程名稱:" + Thread.currentThread().getName() + ",執行" + ii);
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
            }
        }
    ------output-------
    線程名稱:pool-1-thread-3,執行2
    線程名稱:pool-1-thread-1,執行0
    線程名稱:pool-1-thread-2,執行3
    線程名稱:pool-1-thread-3,執行4
    線程名稱:pool-1-thread-1,執行5
    線程名稱:pool-1-thread-2,執行6
    線程名稱:pool-1-thread-3,執行7
    線程名稱:pool-1-thread-1,執行8
    線程名稱:pool-1-thread-3,執行9

newSingleThreadExecutor:

  • 底層:FinalizableDelegatedExecutorService包裝的ThreadPoolExecutor實例,corePoolSize為1;maximumPoolSize為1;keepAliveTime為0L;unit為:TimeUnit.MILLISECONDS;workQueue為:new LinkedBlockingQueue<Runnable>() 無解阻塞隊列
  • 通俗:創建只有一個線程的線程池,且線程的存活時間是無限的;當該線程正繁忙時,對於新任務會進入阻塞隊列中(無界的阻塞隊列)
  • 適用:一個任務一個任務執行的場景
  •   /** 
    *創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行
    */ public static void singleTheadPoolTest() { ExecutorService pool = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { final int ii = i; pool.execute(() -> out.println(Thread.currentThread().getName() + "=>" + ii)); } } -----output-------

     線程名稱:pool-1-thread-1,執行0
     線程名稱:pool-1-thread-1,執行1
     線程名稱:pool-1-thread-1,執行2
     線程名稱:pool-1-thread-1,執行3
     線程名稱:pool-1-thread-1,執行4
     線程名稱:pool-1-thread-1,執行5
     線程名稱:pool-1-thread-1,執行6
     線程名稱:pool-1-thread-1,執行7
     線程名稱:pool-1-thread-1,執行8
     線程名稱:pool-1-thread-1,執行9

NewScheduledThreadPool:

  • 底層:創建ScheduledThreadPoolExecutor實例,corePoolSize為傳遞來的參數,maximumPoolSize為Integer.MAX_VALUE;keepAliveTime為0;unit為:TimeUnit.NANOSECONDS;workQueue為:new DelayedWorkQueue() 一個按超時時間升序排序的隊列
  • 通俗:創建一個固定大小的線程池,線程池內線程存活時間無限制,線程池可以支持定時及周期性任務執行,如果所有線程均處於繁忙狀態,對於新任務會進入DelayedWorkQueue隊列中,這是一種按照超時時間排序的隊列結構
  • 適用:周期性執行任務的場景
  • /**
         * 創建一個定長線程池,支持定時及周期性任務執行。延遲執行
         */
        public static void sceduleThreadPool() {
            ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
            Runnable r1 = () -> out.println("線程名稱:" + Thread.currentThread().getName() + ",執行:3秒后執行");
            scheduledThreadPool.schedule(r1, 3, TimeUnit.SECONDS);
            Runnable r2 = () -> out.println("線程名稱:" + Thread.currentThread().getName() + ",執行:延遲2秒后每3秒執行一次");
            scheduledThreadPool.scheduleAtFixedRate(r2, 2, 3, TimeUnit.SECONDS);
            Runnable r3 = () -> out.println("線程名稱:" + Thread.currentThread().getName() + ",執行:普通任務");
            for (int i = 0; i < 5; i++) {
                scheduledThreadPool.execute(r3);
            }
        }
    ----output------
    線程名稱:pool-1-thread-1,執行:普通任務
    線程名稱:pool-1-thread-5,執行:普通任務
    線程名稱:pool-1-thread-4,執行:普通任務
    線程名稱:pool-1-thread-3,執行:普通任務
    線程名稱:pool-1-thread-2,執行:普通任務
    線程名稱:pool-1-thread-1,執行:延遲2秒后每3秒執行一次
    線程名稱:pool-1-thread-5,執行:3秒后執行
    線程名稱:pool-1-thread-4,執行:延遲2秒后每3秒執行一次
    線程名稱:pool-1-thread-4,執行:延遲2秒后每3秒執行一次
    線程名稱:pool-1-thread-4,執行:延遲2秒后每3秒執行一次
    線程名稱:pool-1-thread-4,執行:延遲2秒后每3秒執行一次

     

三、線程池任務執行流程:

  1. 當線程池小於corePoolSize時,新提交任務將創建一個新線程執行任務,即使此時線程池中存在空閑線程。
  2. 當線程池達到corePoolSize時,新提交任務將被放入workQueue中,等待線程池中任務調度執行
  3. 當workQueue已滿,且maximumPoolSize>corePoolSize時,新提交任務會創建新線程執行任務
  4. 當提交任務數超過maximumPoolSize時,新提交任務由RejectedExecutionHandler處理
  5. 當線程池中超過corePoolSize線程,空閑時間達到keepAliveTime時,關閉空閑線程
  6. 當設置allowCoreThreadTimeOut(true)時,線程池中corePoolSize線程空閑時間達到keepAliveTime也將關閉

四、備注:

  一般如果線程池任務隊列采用LinkedBlockingQueue隊列的話,那么不會拒絕任何任務(因為隊列大小沒有限制),這種情況下,ThreadPoolExecutor最多僅會按照最小線程數來創建線程,也就是說線程池大小被忽略了。如果線程池任務隊列采用

ArrayBlockingQueue隊列的話,那么ThreadPoolExecutor將會采取一個非常負責的算法,比如假定線程池的最小線程數為4,最大為8所用的ArrayBlockingQueue最大為10。隨着任務到達並被放到隊列中,線程池中最多運行4個線程(即最小線程數)。

即使隊列完全填滿,也就是說有10個處於等待狀態的任務,ThreadPoolExecutor也只會利用4個線程。如果隊列已滿,而又有新任務進來,此時才會啟動一個新線程,這里不會因為隊列已滿而拒接該任務,相反會啟動一個新線程。新線程會運行隊列中的

第一個任務,為新來的任務騰出空間。這個算法背后的理念是:該池大部分時間僅使用核心線程(4個),即使有適量的任務在隊列中等待運行。這時線程池就可以用作節流閥。如果擠壓的請求變得非常多,這時該池就會嘗試運行更多的線程來清理;

這時第二個節流閥—最大線程數就起作用了。


免責聲明!

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



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