天天看點

JAVA線程池——ThreadPool前言By the way

前言

線程的使用在 Java 開發中已經屢見不鮮了,在并發程式設計,分布式的場景中更是常客,但是對于線程的使用可能一些職場新人還是會有些不熟悉,結合池化技術的線程池也可能尚未有了解,今天這篇我們就先來說一些Java線程池中的一些基本知識以及原理。

線程池ThreadPool

線程池做的工作主要是控制運作的線程的數量,處理過程中将任務放入隊列,然後線上程建立後啟動這些任務,如果線程數量超過了最大數量超出數量的線程排隊等候,等其它線程執行完畢,再從隊列中取出任務來執行。他的主要特點為:線程複用;控制最大并發數;管理線程。

線程池工作流程

  1. 線程池剛建立時,裡面沒有一個線程。任務隊列是作為參數傳進來的。不過,就算隊列裡面有任務,線程池也不會馬上執行它們。
  2. 當調用 execute() 方法添加一個任務時,線程池會做如下判斷:

    a) 如果正在運作的線程數量小于 corePoolSize,那麼馬上建立線程運作這個任務;

    b) 如果正在運作的線程數量大于或等于 corePoolSize,那麼将這個任務放入隊列;

    c) 如果這時候隊列滿了,而且正在運作的線程數量小于 maximumPoolSize,那麼還是要建立非核心線程立刻運作這個任務;

    d) 如果隊列滿了,而且正在運作的線程數量大于或等于 maximumPoolSize,那麼線程池會抛出異常RejectExecutionException。

  3. 當一個線程完成任務時,它會從隊列中取下一個任務來執行。
  4. 當一個線程無事可做,超過一定的時間(keepAliveTime)時,線程池會判斷,如果目前運作的線程數大于 corePoolSize,那麼這個線程就被停掉。是以線程池的所有任務完成後,它最終會收縮到 corePoolSize 的大小。
    JAVA線程池——ThreadPool前言By the way

線程池參數

老規矩,上代碼,下面是ThreadPoolExector的構造函數:

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.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }
           
  1. int corePoolSize 核心線程數
  2. int maximumPoolSize 最大線程數
  3. long keepAliveTime 目前線程池數量超過corePoolSize時,多餘的空閑線程的存活時間,即多次時間内會被銷毀
  4. TimeUnit unit 時間機關
  5. BlockingQueue workQueue 任務隊列,被送出但尚未被執行的任務
  6. ThreadFactory threadFactory 線程工廠,一般用預設的就好了
  7. RejectedExecutionHandler handler 拒絕政策,當任務太多來不及處理,如何拒絕任務

拒絕政策

線程池中的線程已經用完了,無法繼續為新任務服務,同時,等待隊列也已經排滿了,再也塞不下新任務了。這時候我們就需要拒絕政策機制合理的處理這個問題。 JDK内置的拒絕政策如下:

  1. AbortPolicy : 直接抛出異常,阻止系統正常運作。
  2. CallerRunsPolicy : 隻要線程池未關閉,該政策直接在調用者線程中,運作目前被丢棄的任務。顯然這樣做不會真的丢棄任務,但是,任務送出線程的性能極有可能會急劇下降。
  3. DiscardOldestPolicy : 丢棄最老的一個請求,也就是即将被執行的一個任務,并嘗試再次送出目前任務。
  4. DiscardPolicy : 該政策默默地丢棄無法處理的任務,不予任何處理。如果允許任務丢失,這是最好的一種方案。

以上内置拒絕政策均實作了RejectedExecutionHandler接口,若以上政策仍無法滿足實際需要,完全可以自己擴充RejectedExecutionHandler接口

JDK8自帶線程池

newSingleThreadPool

這個線程池隻有一個核心線程在工作,也就是相當于單線程串行執行所有任務。如果這個唯一的線程因為異常結束,那麼會有一個新的線程來替代它。此線程池保證所有任務的執行順序按照任務的送出順序執行。

  • corePoolSize : 1,隻有一個核心線程在工作
  • maximumPoolSize : 1
  • keepAliveTime : 0L
  • workQueue : new LinkedBlockingQueue(),無界緩沖隊列

newScheduledThreadPool

newScheduledThreadPool是核心線程池固定,大小無限的線程池,此線程池支援定時以及周期性執行任務的需求,建立一個周期性執行任務的線程池。如果閑置,非核心線程池會在DEFAULT_KEEPALIVEMILLIS時間内回收

  • corePoolSize : corePoolSize
  • maximumPoolSize : Integer.MAX_VALUE
  • keepAliveTime : DEFAULT_KEEPALIVE_MILLIS
  • workQueue : new DelayedWorkQueue<>()

newFixedThreadPool

newFixedThreadPool是固定大小的線程池,隻有核心線程,每次送出一個任務就建立一個線程,直到線程達到線程池的最大大小。線程池的大小一旦達到最大值就會保持不變,如果某個線程因為執行異常而結束,那麼線程池會補充一個新線程。多數針對一些很穩定很固定的正規并發線程,多用于伺服器。

  • corePoolSize : nThreads
  • maximumPoolSize : nThreads
  • keepAliveTime : 0L
  • workQueue : new LinkedBlockingQueue(),無界緩沖隊列

newCacheThreadPool

這個是無界線程池,如果線程池大小超過了處理任務所需要的線程,那麼就會回收部分空閑(60秒不執行任務)線程,當任務數增加時,此線程池又可以智能地添加新線程來處理任務。

線程池大小完全依賴于作業系統能夠建立的最大線程大小。SynchronousQueue是一個緩沖區為1的阻塞隊列。

緩存型池子通常用于執行一些生存期很短的異步型任務,是以在一些面向連接配接的daemon型Server中用得不多,但對于生存期短的異步任務,它是Executor的首選。

  • corePoolSize : 0
  • maximumPoolSize : Integer.MAX_VALUE
  • keepAliveTime : 60L
  • workQueue : new SynchronousQueue(),緩沖區為1的阻塞隊列

By the way

有問題?可以給我留言或私聊

有收獲?那就順手點個贊呗~

當然,也可以到我的公衆号下「6曦軒」,

回複“學習”,即可領取一份

【Java工程師進階架構師的視訊教程】~

回複“面試”,可以獲得:

【本人嘔心瀝血整理的 Java 面試題】

回複“MySQL腦圖”,可以獲得

【MySQL 知識點梳理高清腦圖】

由于我咧,科班出身的程式員,php,Android以及硬體方面都做過,不過最後還是選擇專注于做 Java,是以有啥問題可以到公衆号提問讨論(技術情感傾訴都可以哈哈哈),看到的話會盡快回複,希望可以跟大家共同學習進步,關于服務端架構,Java 核心知識解析,職業生涯,面試總結等文章會不定期堅持推送輸出,歡迎大家關注~~~

JAVA線程池——ThreadPool前言By the way