我理解的Java併發基礎(七):線程池和Executors工具類

線程池,顧名思義就是不少線程對象組成的一個組,對外提供執行任務的服務。調用者沒必要要關心線程的管理方面的細節。 在程序中使用線程池的好處: 1,減小內存消耗。每個線程對象對應操做系統中的一個線程,頻繁建立,佔用過多系統內存。 2,提升執行效率。系統建立線程須要時間(win系統耗時,linux能夠忽略),線程對象在堆中的初始化也耗時。 3,管理方便。線程池負責線程的管理,並提供簡單的管理API。調用者只須要負責執行任務的建立。linux

一,ThreadPoolExecutor是建立和管理線程池的類,來看看它經常使用的構造API。多線程

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue)

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

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

ThreadPoolExecutor 構造方法的這幾個參數,也是理解線程池工做的核心概念:併發

1,int corePoolSize,核心線程數。線程池會努力以corePoolSize個數的線程數來執行交給線程池的任務。在沒有任務的時候,核心線程是不會被回收的。工具

2,BlockingQueue<Runnable> workQueue,任務隊列。當線程池執行的任務數超過核心線程數的時候,即核心線程滿載的狀況下,新接受的任務將被存放到該任務隊列中。通常狀況下推薦使用阻塞隊列。 workQueue這裏支持的幾個實現類:ArrayBlockingQueue,LinkedBlockingQueue,SynchronousQueue,PriorityBlockingQueue等。性能

3,int maximumPoolSize,最大線程數。若是線程池接受的任務依然在增長,任務隊列workQueue滿了以後(無界隊列不會滿),會開始建立新的線程來執行任務,直到線程池的總線程數達到maximumPlloSize的大小。操作系統

4,RejectedExecutionHandler handler,拒絕策略。當線程池已經達到了最大線程數,任務隊列workQueue也已經滿了的狀況下,線程池已經沒有能力再處理新的任務了,即線程池處於飽和狀態。若是此時依然有新的任務提交給線程池,則會採起拒絕策略來執行。RejectedExecutionHandler接口就一個方法須要實現,即void rejectedExecution(Runnable r, ThreadPoolExecutor executor)。JDK目前實現RejectedExecutionHandler接口的拒絕策略有4種: 4.1,AbortPolicy,直接拋出異常。 4.2,CallerRunsPolicy,使用任務提交者所在線程執行任務。 4.3,DiscardOldestPolicy,丟棄任務隊列中的頭任務,把新任務添加到隊列尾部。 4.4,DiscardPolicy,直接丟棄,不會拋異常。 固然,開發者也能夠本身實現RejectedExecutionHandler接口來達到自定義的拒絕策略。線程

5,ThreadFactory threadFactory 建立線程的工程。ThreadFactory接口就一個方法Thread newThread(Runnable r)。J.U.C包下就一個實現類DefaultThreadFactory,該類也是threadFactory這個參數若是不指定的時候的默認策略。rest

6,long keepAliveTime 和 TimeUnit unit,空閒時間。當線程池的工做線程空閒一段時間以後,超過核心線程數的線程將會被拋棄。JDK1.6以後,若是顯示調用了public void allowCoreThreadTimeOut(boolean value)這個方法,則核心線程數在必定時間內沒有任務執行的時候,也能夠被拋棄。code

以上的這些構造方法的參數都有對應的public類型的get和set方法。對象

線程池對象在建立後,默認執行任務的時候纔開始一個一個的建立核心線程,知道累計執行了corePoolSize個任務以後才完成了核心線程的初始化。調用prestartAllCoreThreads()後能夠提早完成核心線程的初始化工做。

ThreadPoolExecutor 執行任務的API:

public void execute(Runnable command)

public <T> Future<T> submit(Callable<T> task)

ThreadPoolExecutor接受兩種類型的參數來執行任務。一種是Runnable接口類型,一種是Callable類型。後者能夠返回一個Future對象,經過future對象的get方法能夠獲取該任務的執行結果。

二,監控、關閉和擴展線程池的API:

public void shutdown(); // 關閉線程池。設置每一個正在執行任務的線程的狀態interrupt中斷標識。因此沒法相應中斷表示的任務可能永遠沒法終止。

public List<Runnable> shutdownNow(); // 關閉線程池,並返回workQueue中的Runnable對象的List。

public boolean isShutdown(); // 調用shutdown()或者shutdownNow()方法後,isShutdown()返回true。

public boolean isTerminated(); // 調用shutdown()或者shutdownNow()方法後,全部任務都已關閉後,isTerminated()返回true。

public boolean remove(Runnable task); // 若是task在workQueue中,則移除。

public void purge(); // Callable類型的任務返回的Future類型的對象能夠調用future.cancell()來取消執行。調用purge()用來清理workQueue任務隊列中已經被cancell的任務。

public int getPoolSize(); // 獲取當前線程池中的線程數量。

public int getActiveCount(); // 獲取正在執行任務的線程數。

public int getLargestPoolSize(); // 獲取線程池中曾經建立過的最大線程數量。

public long getTaskCount(); // 獲取線程池中的任務數量,包括正在被執行的線程。

public long getCompletedTaskCount(); // 線程已經執行完了任務,可是尚未執行新的任務,好比正在執行afterExecute()方法,獲取處於這個狀態的線程的個數。

protected void beforeExecute(Thread t, Runnable r); // 供開發者擴展的方法,在任務執行以前會調用此方法。

protected void afterExecute(Runnable r, Throwable t); // 供開發者擴展的方法,在任務執行完成以後會調用此方法。

protected void terminated(); // 供開發者擴展的方法,線程池關閉以前會調用此方法。

3、合理配置線程池。根據任務的特性,選擇合適的構造參數來構造線程池。

1,若是是CPU密集型的任務,配置較小的線程數。如:線程池核心數=CPU核心數+1; 2,若是是IO密集型的任務,能夠配置較大的線程數。如:線程池核心數=CPU核心數*2; 3,混合型的任務能夠嘗試分拆爲CPU密集型和IO密集型,再使用不一樣的線程池來處理; 4,能夠經過Runtime.getRuntime().availableProcessors()獲取當前設備的CPU核心數。

4、Executors工具類 jdk提供的Executors工具類 封裝了一些經常使用的線程池使用場景類。

1,Runnable和Callable的區別與聯繫。 兩者都是封裝了任務的對象類。前者能夠經過線程池的void execute(Runnable command)來執行,返回值爲void;後者只可以經過線程池的<T> Future<T> submit(Callable<T> task)來執行,返回future對象經過調用get()方法組設獲取返回值或者future的其餘方法完成更多操做。

2,經過Executors工具類建立FixedThreadPool。 FixedThreadPool線程池屬於ThreadPoolExecutor的一種。核心線程數固定且等於最大線程數,隊列採用LinkedBlockingQueue。該線程池的特色是採用固定大小數量的線程來處理任務,任務隊列順序執行,幾乎無界。參見其構造方法:

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

3,經過Executors工具類建立SingleThreadExecutor。 SingleThreadExecutor線程池屬於ThreadPoolExecutor的一種。核心線程數=最大線程數=1,隊列採用LinkedBlockingQueue。該線程池的特色是採用單線程來處理任務,避免併發衝突。任務隊列順序執行,幾乎無界 。參見其構造方法:

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

4,經過Executors工具類建立CachedThreadPool。 CachedThreadPool線程池屬於ThreadPoolExecutor的一種。核心線程數=0,最大線程數=Integer.MAX_VALUE,隊列採用SynchronousQueue。該線程池的特色是隊列不存任務,每一個任務都有單獨的線程執行(全量併發)。參見其構造方法:

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

5,ScheduledThreadPoolExecutor ScheduledThreadPoolExecutor是ThreadPoolExecutor的子類,用來執行週期性或定時任務。參見其構造方法:

public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

特殊指出在於隊列採用了DelayedWorkQueue,而DelayedWorkQueue是ScheduledThreadPoolExecutor的內部實現類,具備DelayQueue和PriorityQueue的特性。DelayQueue用於實現定時任務,結合PriorityQueue按time進行排序能夠實現總體任務的定時特性。

6,經過Executors工具類建立ScheduledThreadPool。 ScheduledThreadPool 線程池屬於ScheduledThreadPoolExecutor 的一種。核心線程數固定,提升任務執行效率。參見其構造方法:

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

7,經過Executors工具類建立SingleThreadScheduledExecutor。 SingleThreadScheduledExecutor線程池屬於ScheduledThreadPoolExecutor 的一種。核心線程數=1,避免併發衝突。參見其構造方法:

public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }

tips: 首選Executor的cachedThreadPool,只有任務數瞬時過大或者這種方式引起性能問題時,才切換爲FixedThreadPool。SingleThreadExecutor是線程數量爲1的FixedThreadPool,遇到多任務時會排隊執行。

相關文章
相關標籤/搜索