線程池,顧名思義就是不少線程對象組成的一個組,對外提供執行任務的服務。調用者沒必要要關心線程的管理方面的細節。 在程序中使用線程池的好處: 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,遇到多任務時會排隊執行。