天天看點

知識點---線程---線程池線程池

線程池

  • 線程池
    • 為什麼要使用線程池?
    • 接口
      • Executors 提供四種線程池:
    • 線程池相關參數的概念:
    • 線程池的工作流程圖
    • 線程池的關閉
    • 問題

線程池

線程池,其實就是一個容納多個線程的容器,其中的線程可以反複使用,省去了頻繁建立線程對象的操作,無需反複建立線程而消耗過多資源。

為什麼要使用線程池?

在java中,如果每個請求到達就建立一個新線程,開銷是相當大的。在實際使用中,建立和銷毀線程花費的時間和消耗的系統資源都相當大,甚至可能要比在處理實際的使用者請求的時間和資源要多的多。除了建立和銷毀線程的開銷之外,活動的線程也需要消耗系統資源。如果在一個jvm裡建立太多的線程,可能會使系統由于過度消耗記憶體或“切換過度”而導緻系統資源不足。為了防止資源不足,需要采取一些辦法來限制任何給定時刻處理的請求數目,盡可能減少建立和銷毀線程的次數,特别是一些資源耗費比較大的線程的建立和銷毀,盡量利用已有對象來進行服務。

接口

Java裡面線程池的頂級接口是 Executor,不過真正的線程池接口是 ExecutorService, ExecutorService 的預設實作是 ThreadPoolExecutor;

Executors:線程池建立工廠類

普通類 Executors 裡面調用的就是 ThreadPoolExecutor。

Executors 類提供工廠方法用來建立不同類型的線程池。比如: newSingleThreadExecutor() 建立一個隻有一個線程的線程池,newFixedThreadPool(int numOfThreads)來建立固定線程數的線程池,newCachedThreadPool()可以根據需要建立新的線程,但如果已有線程是空閑的會重用已有線程。

知識點---線程---線程池線程池
知識點---線程---線程池線程池

1、在建立了線程池後,線程池中的線程數為零。

2、當調用 execute()方法添加一個請求任務時,線程池會做出如下判斷:

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

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

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

2.4 如果隊列滿了且正在運作的線程數量大于或等于 maximumPoolSize,那麼線程池會啟動飽和拒絕政策來執行。

當送出的任務數大于(workQueue.size() +maximumPoolSize ),就會觸發線程池的拒絕政策。

3、當一個線程完成任務時,它會從隊列中取下一個任務來執行。

4、當一個線程無事可做超過一定的時間(keepAliveTime)時,線程會判斷:

4.1 如果目前運作的線程數大于 corePoolSize,那麼這個線程就被停掉。

4.2 是以線程池的所有任務完成後,它最終會收縮到 corePoolSize 的大小。

Executors 提供四種線程池:

1)newSingleThreadExecutor

線程池根據需求建立線程,可擴容,遇強則強(銀行一共10個視窗,隻開放了3個視窗,其他7個視窗沒有開放,如果人很多就要開放其餘的視窗,高峰結束再回複到3個視窗狀态)

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

特點:

1、線程池中數量沒有固定,可達到最大值(Interger. MAX_VALUE)

2、線程池中的線程可進行緩存重複利用和回收(回收預設時間為 1 分鐘)

3、當線程池中,沒有可用線程,會重新建立一個線程

場景: 适用于建立一個可無限擴大的線程池,伺服器負載壓力較輕,執行時間較短,任務多的場景。

2)newFixedThreadPool

一個任務一個任務執行,一池一線程(例如視窗隻能服務一個人,後面來的隻能等待)

建立是一個單線程池,也就是該線程池隻有一個線程在工作,所有的任務是串行執行的,如果這個唯一的線程因為異常結束,那麼會有一個新的線程來替代它,

此線程池保證所有任務的執行順序按照任務的送出順序執行。

特點: 線程池中最多執行 1 個線程,之後送出的線程活動将會排在隊列中以此執行

場景: 适用于需要保證順序執行各個任務,并且在任意時間點,不會同時有多個線程的場景。

3)newFixedThreadPool (int) 一池N線程

建立固定大小的線程池,每次送出一個任務就建立一個線程,直到線程達到線程池的最大大小,線程池的大小一旦達到最大值就會保持不變。

特征:

1、線程池中的線程處于一定的量,可以很好的控制線程的并發量

2、線程可以重複被使用,在顯示關閉之前,都将一直存在

3、超出一定量的線程被送出時候需在隊列中等待

場景: 适用于可以預測線程數量的業務中,或者伺服器負載較重,對線程數有嚴格限制的場景

4)newScheduledThreadPool (了解)

建立一個大小無限的線程池,此線程池支援定時以及周期性執行任務的需求。

線程池相關參數的概念:

public threadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit timeUnit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory){
        this(corePoolSize,maximumPoolSize,keepAliveTime,
                timeUnit, workQueue,threadFactory,defaultHandler);
    }
           

1)corePoolSize:3

線程池的核心線程數(常駐線程數)

一般情況下不管有沒有任務都會一直線上程池中一直存活

2)maximumPoolSize: 7

線程池所能容納的最大線程數,當活動的線程數達到這個值後,後續的新任務将會被阻塞。

3)keepAliveTime:4

線程閑置時的逾時時長

控制線程閑置時的逾時時長,超過則終止該線程。一般情況下用于非核心線程

4)unit:

用于指定 keepAliveTime 參數的時間機關,TimeUnit 是個 enum 枚舉類型,常用的有:TimeUnit.HOURS(小時)、TimeUnit.MINUTES(分鐘)、TimeUnit.SECONDS(秒) 和 TimeUnit.MILLISECONDS(毫秒)等。

5)workQueue:任務隊列(阻塞隊列)

當核心線程數達到最大時,新任務會放在隊列中排隊等待執行。

6)threadFactory:線程工廠

線程工廠,它是一個接口,用來為線程池建立新線程的。

7)RejectedExecutionHandler handler: 拒絕政策(銀行有10個視窗,核心是3個視窗,所有視窗都開放,等待的座位也坐滿了,銀行再來新的顧客,銀行沒有能力接受新的顧客,銀行就要做一個拒絕政策,建議去别的銀行)

線程池的工作流程圖

知識點---線程---線程池線程池
知識點---線程---線程池線程池

線程池的關閉

ThreadPoolExecutor 提供了兩個方法,用于線程池的關閉,分别是 shutdown() 和 shutdownNow()。

shutdown():不會立即的終止線程池,而是要等所有任務緩存隊列中的任務都執行完後才終止,但再也不會接受新的任務。

shutdownNow():立即終止線程池,并嘗試打斷正在執行的任務,并且清空任務緩存隊列,傳回尚未執行的任務。

問題

1、什麼是 Executor 架構?

Executor架構在Java 5中被引入,Executor 架構是一個根據一組執行政策調用、排程、執行和控制的異步任務的架構。

無限制的建立線程會引起應用程式記憶體溢出,是以建立一個線程池是個更好的的解決方案,因為可以限制線程的數量并且可以回收再利用這些線程。利用 Executor 架構可以非常友善的建立一個線程池。

2、Executors 類是什麼?

Executors為Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 類提供了一些工具方法。Executors 可以用于友善的建立線程池。

繼續閱讀