溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java線程池全面知識點總結

發布時間:2021-10-29 11:15:56 來源:億速云 閱讀:157 作者:iii 欄目:開發技術

本篇內容介紹了“Java線程池全面知識點總結”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

原理

線程池的原理非常簡單,這里用處理流程來概括:

  • 線程池判斷核心池里的線程是否都在執行任務,如果不是,創建一個新的線程來執行任務;

  • 如果核心線程池已滿,則將新任務存在工作隊列中;

  • 如果工作隊列滿了,線程數量沒有達到線程池上限的前提下,新建一個線程來執行任務;

  • 線程數量達到上限,則觸發飽和策略來處理這個任務;

使用工作隊列,是為了盡可能降低線程創建的開銷。工作隊列用阻塞隊列來實現。

阻塞隊列

阻塞隊列(BlockingQueue)是指支持阻塞的插入和移除元素的隊列。

  • 阻塞的插入:當隊列滿時,阻塞插入元素的線程,直到隊列不滿;

  • 阻塞的移除:當隊列為空,阻塞移除元素的線程,直到隊列不為空;

原理:使用通知者模式實現。當生產者往滿的隊列中添加元素時,會阻塞生產者。消費者移除元素時,會通知生產者當前隊列可用。

阻塞隊列有以下三種類型,分別是:

  • 有界阻塞隊列:ArrayBlockingQueue(數組),LinkedBlockingQueue(鏈表)

  • 無界阻塞隊列:LinkedTransferQueue(鏈表),PriorityBlockingQueue(支持優先級排序),DelayQueue(支持延時獲取元素的無界阻塞隊列)

  • 同步移交隊列:SynchronousQueue

有界阻塞隊列

主要包括ArrayBlockingQueue(數組),LinkedBlockingQueue(鏈表)兩種。有界隊列大小與線程數量大小相互配合,隊列容量大線程數量小時,可減少上下文切換降低cpu使用率,但是會降低吞吐量。

無界阻塞隊列

比較常用的是LinkedTransferQueue。FixedThreadPool就是用這個實現的。無界阻塞隊列要慎重使用,因為在某些情況,可能會導致大量的任務堆積到隊列中,導致內存飆升。

同步移交隊列

SynchronousQueue。不存儲元素的阻塞隊列,每一個put操作必須等待一個take操作,否則不能繼續添加元素。用于實現CachedThreadPool線程池。

各個線程池所使用的任務隊列映射關系如下:

線程池阻塞隊列

FixedThreadPoolLinkedBlockingQueueSingleThreadExecutorLinkedBlockingQueueCachedThreadExecutorSynchronousQueueScheduledThreadPoolExecutorLinkedBlockingQueue

實現類分析

ThreadPoolExecutor是Java線程池的實現類,是Executor接口派生出來的最核心的類。依賴關系圖如下:

Java線程池全面知識點總結

這里不得不提到Executor框架,該框架包含三大部分,如下:

  • 任務。被執行任務需要實現的接口:Runnable和Callable;

  • 任務執行。即上述核心接口Executor以及繼承而來的ExecutorService。ExecutorService派生出如下兩個類:ThreadPoolExecutor:線程池核心實現類;ScheduledThreadPoolExecutor:用來做定時任務;

  • 異步計算的結果。接口Future和實現Future接口的FutureTask類。線程池創建

new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, milliseconds, runnableTaskQueue, handler)

構造方法如下:

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;
}

參數說明:

  • corePoolSize:核心池的線程數量;

  • workQueue:用于保存任務的工作隊列;

  • maximumPoolSize:最大線程池的大??;

  • keepAliveTime:當線程數量大于核心池線程數量時,keepAliveTime為多余的空閑線程等待新任務的最長時間,超過這個時間,多余的線程會被終止;

  • TimeUnit:keepAliveTime的單位;

  • ThreadFactory:線程工廠,可以給線程設置名字;

  • handler:飽和策略。當隊列和線程池都滿了,會觸發飽和策略,來處理新提交的任務。飽和策略以下幾種:AbortPolicy:直接拋出異常;CallerRunsPolicy:只用調用者所在線程來運行任務;DiscardOldestPolicy:丟棄最近一個任務并執行當前任務;DiscardPolicy:不處理,丟棄掉。

使用Executors創建線程池

使用工具類Executors可創建三種類型的線程池:FixedThreadPool、SingleThreadExecutor、CachedThreadPool。本質上也是調用上述構造方法。理解了前文的參數解釋,下面三種線程池也就容易理解了。

FixedThreadPool

可重用固定線程數的線程池。

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

工作流程如下:

  • 如果當前運行的線程數少于corePoolSize,則創建新線程來執行任務;

  • 線程數等于corePoolSize之后,新任務加入LinkedBlockingQueue(無界阻塞隊列)。因為最大線程數maximumPoolSize參數值等于corePoolSize,不會產生多余線程;

  • 線程執行完任務之后會反復從LinkedBlockingQueue中獲取任務來執行。

SingleThreadExecutor

單個worker線程的線程池

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

SingleThreadExecutor與FixedThreadPool的區別在于,maximumPoolSize和corePoolSize都設置成了1,其它參數都一樣。

  • CachedThreadPool

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

CachedThreadPool將corePoolSize設置為0,maximumPoolSize設置為無限大,同時使用了一個沒有容量的工作隊列SynchronousQueue。這個線程池沒有固定的核心線程,而是根據需要創建新線程。

工作流程:

  • 有新任務時,主線程執行SynchronousQueue.offer操作,空閑線程執行SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS)操作,配對成功則將任務交給空閑線程執行;

  • 當沒有空閑線程時,上面的配對操作失敗,此時會創建一個新線程來執行任務;

  • 任務執行完畢后,空閑線程會等待60秒。60秒內如果有新任務,就立即執行,否則時間一過線程就終止。

線程池關閉

調用shutdown或者shutdownNow方法可關閉線程池。原理是遍歷線程池中所有工作線程,調用interrupt方法來中斷線程。

  • shutdown:將線程置為SHUTDOWN狀態,不能接受新的任務,等待所有任務執行完畢;

  • shutdownNow:將線程置為STOP狀態,不能接受新的任務,嘗試去終止正在執行的惡任務;

這里涉及到ThreadPoolExecutor中定義的線程的五種狀態

// runState is stored in the high-order bits
private static final int RUNNING    = -1 << COUNT_BITS;
private static final int SHUTDOWN   =  0 << COUNT_BITS;
private static final int STOP       =  1 << COUNT_BITS;
private static final int TIDYING    =  2 << COUNT_BITS;
private static final int TERMINATED =  3 << COUNT_BITS;
  • RUNNING:接受新任務,處理任務;

  • SHUTDOWN:不接受新任務,但會把隊列中任務處理完;

  • STOP:不接受新任務,不處理隊列中的任務,并且終止正在處理的任務;

  • TIDYING:正在執行的任務和隊列都為空,進入該狀態,將要執行terminated();

  • TERMINATED:所有terminated()方法執行完畢,線程池徹底終止。

當隊列和正在執行的任務都為空時,由SHUTDOWN轉化為TIDYING;當正在執行的任務為空,由STOP轉化為TIDYING。

“Java線程池全面知識點總結”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女