Java線程池簡單介紹

Java 線程池介紹

一、線程池

線程池,從字面含義來看,是指管理一組同構工作線程的資源池。線程池是與工作隊列密切相關的,其中在工作隊列中保存了所有等待執行的任務。工作者線程的任務很簡單:從工作隊列中獲取一個任務,執行任務,然後返回線程池並等待下一個任務。

跟數據庫連接池相似,如果每一次操作,都要新建一個線程(連接)然後銷燬,會對系統資源產生巨大開銷,通過線程池(連接池)對線程(連接)進行管理,讓一些線程(連接)一直存在,既可以減少新建銷燬的資源浪費,也可以提高系統的響應性。

二、Java 中的線程池類

在 Java1.8 中,已經在 Executors 中封裝好了幾種線程池的靜態實現方法,這些方法都是調用統一的線程池構建函數來構建這幾種線程池,這幾種線程池分別是:

  • newCacheThreadPool:創建一個具有緩存功能的線程池,系統根據需要創建線程,這些線程將會被緩存在線程池中。
  • newFixedThreadPool:創建一個可重用的、具有固定線程數的線程池。
  • newSingleThreadExecutor:創建一個只有單線程的線程池,它相當於調用 newFixedThreadPool 時設置大小爲 1.
  • newScheduledThreadPool:創建具有指定線程數的線程池,它可以在指定延遲後執行線程任務。
  • newSingleScheduledThreadPool:創建只有一個線程的線程池,它可以在指定延遲後執行線程任務。
  • newWorkStealingPool:創建持有足夠的線程的線程池來支持給定的並行級別,該方法還會使用多個隊列來減少競爭。該線程池相當於後臺線程池,如果所有前臺線程都結束了,線程池中的線程就會自動死亡。

除了具有延遲功能的線程池返回的是 ScheduledExecutorService 類外,其餘方法的返回值都是接口 ExecutorService 。

在 Java 中還有一種比較特殊的線程池 ForkJoinPool ,他是 ExecutorService 的一個實現類,主要作用是將一個任務拆分成多個小任務並行計算,然後再合併計算結果,它的線程數量取決於CPU的數量

下面來放張圖看看 Java 關於線程的脈絡:

uwO2DJ.png

左邊是線程池相關的,右邊的是 Future 相關的。Future 是對線程的一種包裝,可以通過 Future 獲取線程的一些信息,比如線程是否運行,線程返回值等。

我們分析一下 ScheduledExecutorService 和 ExecutorService 中的一些方法,這些方法只列出了包含所有參數的方法,能省略的參數可以自行查看 API 文檔:

ExecutorService

代表儘快執行線程的線程池,只要線程池中有空閒線程,就立即執行線程任務:

  • <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit):執行給定的任務集合,並在所有任務完成或超時後(即 unit 參數)返回所有任務的 Future 集合,超時未完成的任務將會被取消,如果任務拋出異常也當作已完成。
  • <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) :執行給定的任務集合,一旦有任務完成或拋出異常,就返回完成任務的結果(拋出異常無結果),超時與上面方法一致。
  • boolean awaitTermination(long timeout, TimeUnit unit):阻塞當前進程直到所有任務完成或超時或拋出異常。
  • boolean isTermination():如果所有任務在關閉後都已完成,則返回 true。注:除非先調用 shutdown 或 shutdownNow,否則 isTerminated 永遠不會爲真。
  • void shutdown():啓動有序關閉,在該關閉中執行先前提交的任務,但不接受任何新任務。
  • List<Runnable> shutdownNow():嘗試停止所有正在執行的任務,暫停正在等待的任務的處理,並返回正在等待執行的任務的列表。任何無法響應中斷的任務都可能永遠不會終止。
  • boolean isShutdown():如果此執行程序已關閉,則返回 true。
  • Future<?> submit(Runnable task):提交一個 Runnable 任務以執行並返回一個表示該任務的 Future。成功完成後,Future 的 get 方法將返回 null。

ScheduledExecutorService

代表可在指定延遲後或週期性地執行線程任務地線程池

  • <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit):指定 callable 任務將在 delay 延遲後執行。
  • ScheduledFuture<V> schedule(Runnable command, long delay, TimeUnit unit):指定 command 任務將在 delay 延遲後執行。
  • ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit):指定 command 任務將在 delay 延遲後執行,而且以設定頻率重複執行。也就是說,在 initialDelay 後開始執行,依次在 initialDelay+period,initialDelay+2*period 處重複執行,以此類推。
  • ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit):創建並執行一個在給定初始延遲後首次啓用的定期操作,隨後在每一次執行終止和下一個執行開始之間都存在給定的延遲。如果任務在任一次執行時遇到異常,就會取消後續執行,否則,只能通過程序來顯式取消或終止該任務。

三、自定義線程池的創建

我們可以看一下線程池的構造函數,在 ThreadPoolExecutor 類中一共有以下四種構造方法:

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, 
			long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, 
			long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, 
			RejectedExecutionHandler handler)
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, 
			long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, 
			ThreadFactory threadFactory)
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, 
			long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, 
			ThreadFactory threadFactory, RejectedExecutionHandler handler)

參數介紹:

  • corePoolSize - 即使線程池空閒,也要保留的線程數量。
  • maximumPoolSize - 線程池中允許的最大線程數。
  • keepAliveTime - 當線程數大於內核數(即線程池中的線程大於 corePoolSize)時,這是多餘的空閒線程將在終止之前等待新任務的最長時間,時間到後多餘線程會銷燬。如果調用了 allowCoreThreadTimeOut(boolean) 方法,傳入 true,則核心線程池數量也會像普通線程一樣被逐漸關閉,直到線程池大小爲 0.
  • unit - keepAliveTime 參數的時間單位。
  • workQueue - 在執行任務之前用於保留任務的阻塞隊列。此隊列將僅保存 execute 方法提交的 Runnable 任務。
  • threadFactory - 執行程序創建新線程時要使用的工廠。
  • handler - 因達到線程池最大數量和隊列容量而被阻止執行時使用的處理程序,也稱爲拒絕策略。

阻塞隊列
java.util.concurrent.BlockingQueue 接口有以下阻塞隊列的實現:

  • FIFO 隊列 :LinkedBlockingQueue、ArrayBlockingQueue(固定長度)
  • 優先級隊列 :PriorityBlockingQueue

阻塞隊列提供了阻塞的 take() 和 put() 方法:如果隊列爲空 take() 將阻塞,直到隊列中有內容;如果隊列爲滿 put() 將阻塞,直到隊列有空閒位置。線程池的排隊策略與 BlockingQueue 有關,詳情可參考Java 併發編程:阻塞隊列

拒絕策略
拒絕策略是 ThreadPoolExecutor 中的常量:

  • ThreadPoolExecutor.AbortPolicy:丟棄任務並拋出 RejectedExecutionException 異常。
  • ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,但是不拋出異常。
  • ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然後重新嘗試執行任務(重複此過程)
  • ThreadPoolExecutor.CallerRunsPolicy:由調用線程處理該任務

Java 中封裝好的線程池就是調用上面的構造函數來創建的,不過他設置好了對應的參數,而延遲線程池的構造方法的參數與普通線程池的構造方法的參數相似,這裏就不再重複。

以上就是線程池的簡單介紹和創建。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章