《java筆記系列》線程池Executor

《Java線程池》Executor 以及Executors

線程池的相關類的體系結構如下:

先看Executor接口,是最根上的接口


    public interface Executor {

        /*
         * Executes the given command at some time in the future.  The command
         * may execute in a new thread, in a pooled thread, or in the calling
         * thread, at the discretion of the {@code Executor} implementation.
         *翻譯:
         1、任務可能在將來的某個時刻被執行,即可能不是立即執行
         2、任務可能在新的線程中被執行,
         新線程可能是線程池中的,也可能是被調用的線程。這取決於對Executor的實現
         */
        void execute(Runnable command);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

首先Executor的execute方法只是執行一個Runnable的任務,當然了從某種角度上將最後的實現類也是在線程中啓動此任務的。根據線程池的執行策略最後這個任務可能在新的線程中執行,或者線程池中的某個線程,甚至是調用者線程中執行(相當於直接運行Runnable的run方法)。這點在後面會詳細說明。

ExecutorService在Executor的基礎上增加了一些方法,其中有兩個核心的方法:

1、Future<?> submit(Runnable task)

2、<T> Future<T> submit(Callable<T> task)
  • 1
  • 2
  • 3

這兩個方法都是向線程池中提交任務,它們的區別在於Runnable在執行完畢後沒有結果,Callable執行完畢後有一個結果。這在多個線程中傳遞狀態和結果是非常有用的。另外他們的相同點在於都返回一個Future對象。Future對象可以阻塞線程直到運行完畢(獲取結果,如果有的話),也可以取消任務執行,當然也能夠檢測任務是否被取消或者是否執行完畢。在沒有Future之前我們檢測一個線程是否執行完畢通常使用Thread.join()或者用一個死循環加狀態位來描述線程執行完畢。現在有了更好的方法能夠阻塞線程,檢測任務執行完畢甚至取消執行中或者未開始執行的任務。

ScheduledExecutorService描述的功能和Timer/TimerTask類似,解決那些需要任務重複執行的問題。這包括延遲時間一次性執行、延遲時間週期性執行以及固定延遲時間週期性執行等。當然了繼承ExecutorService的ScheduledExecutorService擁有ExecutorService的全部特性。

ThreadPoolExecutor是ExecutorService的默認實現,ThreadPoolExecutor並不是直接實現的ExecutorService接口,而是繼承AbstractExecutorService抽象類。AbstractExecutorService抽象類實現了ExecutorService接口。ThreadPoolExecutor其中的配置、策略也是比較複雜的,在後面的章節中會有詳細的分析。

public class ThreadPoolExecutor extends AbstractExecutorService ;
  • 1

ScheduledThreadPoolExecutor是繼承ThreadPoolExecutor的ScheduledExecutorService接口實現,週期性任務調度的類實現,繼承體系如下,在後面的章節中會有詳細的分析。

    public class ScheduledThreadPoolExecutor
        extends ThreadPoolExecutor
        implements ScheduledExecutorService
  • 1
  • 2
  • 3

這裏需要稍微提一下的是CompletionService接口,它是用於描述順序獲取執行結果的一個線程池包裝器。它依賴一個具體的線程池調度,但是能夠根據任務的執行先後順序得到執行結果,這在某些情況下可能提高併發效率。

要配置一個線程池是比較複雜的,尤其是對於線程池的原理不是很清楚的情況下,很有可能配置的線程池不是較優的,因此在Executors類裏面提供了一些靜態工廠,生成一些常用的線程池。

1、newSingleThreadExecutor:創建一個單線程的線程池。這個線程池只有一個線程在工作,也就是相當於單線程串行執行所有任務。如果這個唯一的線程因爲異常結束,那麼會有一個新的線程來替代它。此線程池保證所有任務的執行順序按照任務的提交順序執行。

2、newFixedThreadPool:創建固定大小的線程池。每次提交一個任務就創建一個線程,直到線程達到線程池的最大大小。線程池的大小一旦達到最大值就會保持不變,如果某個線程因爲執行異常而結束,那麼線程池會補充一個新線程。

3、newCachedThreadPool:創建一個可緩存的線程池。如果線程池的大小超過了處理任務所需要的線程,那麼就會回收部分空閒(60秒不執行任務)的線程,當任務數增加時,此線程池又可以智能的添加新線程來處理任務。此線程池不會對線程池大小做限制,線程池大小完全依賴於操作系統(或者說JVM)能夠創建的最大線程大小。

4、newScheduledThreadPool:創建一個大小無限的線程池。此線程池支持定時以及週期性執行任務的需求。

5、newSingleThreadScheduledExecutor:創建一個單線程的線程池。此線程池支持定時以及週期性執行任務的需求。

小結

關於Executor,我們需要了解它的體系結構,這樣我們就能更容易的理清楚他們的關係。

關於Executors,我們需要記住他所能產生的幾種線程池的方法,以及產生的每個線程池的類別是什麼,這個要相當的清楚,這樣我們就可以在合適的場景使用合適的線程池。

現在回顧一下:

1、newSignalThreadExecutor():產生單線程的線程池,即只有一個線程來順序執行任務隊列中的任務。當此線程因異常結束,則產生一個新的線程來補充。

2、newFixdThreadPool():產生固定個數的線程池。

3、newCachedThreadPool(int num):產生一個緩存線程池,即當線程數大於任務數之後回收多餘的線程。

4、newScheduledThreadPool():產生一個支持週期性執行任務的線程池。例如:

//創建一個線程數爲5的線程池,支持週期執行任務
    ScheduledExecutorService exec = Executors.newScheduledThreadPool(5);
  • 1
  • 2
  • 3

5、newSignalScheduledThreadPool():產生一個單個線程的線程池,且線程池支持週期性執行任務。

參考資料

1、http://www.blogjava.net/xylz/archive/2010/12/21/341281.html

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