java.util.concurrent.Executor : 負責線程的使用與調度的根接口
|–ExecutorService:Executor的子接口,線程池的主要接口
|–ThreadPoolExecutor:ExecutorService的實現類
|–ScheduledExecutorService:ExecutorService的子接口,負責線程的調度
|–ScheduledThreadPoolExecutor:既繼承了ThreadPoolExecutor,同時實現了ScheduledExecutorServicehtml
在實際使用過程當中,咱們不須要本身手動new出線程池,juc的工具類Executors爲咱們提供了方法用以建立線程池: (注意:最近阿里發佈的 Java開發手冊中強制線程池不容許使用 Executors 去建立,而是經過 ThreadPoolExecutor 的方式,這樣的處理方式讓寫的同窗更加明確線程池的運行規則,規避資源耗盡的風險。下面轉載部分有較爲詳細的介紹)java
ExecutorService newFixedThreadPool() : 建立固定大小的線程池
ExecutorService newCachedThreadPool() : 緩存線程池,線程池的數量不固定,能夠根據需求自動的更改數量。
ExecutorService newSingleThreadExecutor() : 建立單個線程池。線程池中只有一個線程
ScheduledExecutorService newScheduledThreadPool() : 建立固定大小的線程池,能夠延遲或定時的執行任務。面試
最近看阿里的 Java開發手冊,上面有線程池的一個建議:數組
【強制】線程池不容許使用 Executors 去建立,而是經過 ThreadPoolExecutor 的方式,
這樣的處理方式讓寫的同窗更加明確線程池的運行規則,規避資源耗盡的風險。緩存
結合最近面試的經歷,發現這條建議仍是十分有用的,由於本身常常使用Executors提供的工廠方法建立線程池,因此忽略了線程池內部的實現。
特別是拒絕策略,面試被問到兩次,由於使用Executors建立線程池不會傳入這個參數而使用默認值因此咱們經常忽略這一參數,還好由於這條建議,本身提早熟悉了一下ThreadPoolExecutor。markdown
先看看如何使用ThreadPoolExecutor建立線程池:工具
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
corePoolSize - 線程池核心池的大小。
maximumPoolSize - 線程池的最大線程數。
keepAliveTime - 當線程數大於核心時,此爲終止前多餘的空閒線程等待新任務的最長時間。
unit - keepAliveTime 的時間單位。
workQueue - 用來儲存等待執行任務的隊列。
threadFactory - 線程工廠。
handler - 拒絕策略。post
線程池有兩個線程數的設置,一個爲核心池線程數,一個爲最大線程數。
在建立了線程池後,默認狀況下,線程池中並無任何線程,等到有任務來才建立線程去執行任務,除非調用了prestartAllCoreThreads()或者prestartCoreThread()方法
當建立的線程數等於 corePoolSize 時,會加入設置的阻塞隊列。當隊列滿時,會建立線程執行任務直到線程池中的數量等於maximumPoolSize。spa
java.lang.IllegalStateException: Queue full
方法 拋出異常 返回特殊值 一直阻塞 超時退出
插入方法 add(e) offer(e) put(e) offer(e,time,unit)
移除方法 remove() poll() take() poll(time,unit)
檢查方法 element() peek() 不可用 不可用操作系統
ArrayBlockingQueue :一個由數組結構組成的有界阻塞隊列。
LinkedBlockingQueue :一個由鏈表結構組成的有界阻塞隊列。
PriorityBlockingQueue :一個支持優先級排序的無界阻塞隊列。
DelayQueue: 一個使用優先級隊列實現的無界阻塞隊列。
SynchronousQueue: 一個不存儲元素的阻塞隊列。
LinkedTransferQueue: 一個由鏈表結構組成的無界阻塞隊列。
LinkedBlockingDeque: 一個由鏈表結構組成的雙向阻塞隊列。
ThreadPoolExecutor.AbortPolicy: 丟棄任務並拋出RejectedExecutionException異常。 (默認)
ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,可是不拋出異常。
ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,而後從新嘗試執行任務(重複此過程)
ThreadPoolExecutor.CallerRunsPolicy:由調用線程處理該任務
說明:Executors 各個方法的弊端:
1)newFixedThreadPool 和 newSingleThreadExecutor:
主要問題是堆積的請求處理隊列可能會耗費很是大的內存,甚至 OOM。
2)newCachedThreadPool 和 newScheduledThreadPool:
主要問題是線程數最大數是 Integer.MAX_VALUE,可能會建立數量很是多的線程,甚至 OOM。
讓咱們再看看Executors提供的那幾個工廠方法。
建立一個單線程的線程池。這個線程池只有一個線程在工做,也就是至關於單線程串行執行全部任務。若是這個惟一的線程由於異常結束,那麼會有一個新的線程來替代它。
此線程池保證全部任務的執行順序按照任務的提交順序執行。
new ThreadPoolExecutor(1, 1,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
建立固定大小的線程池。每次提交一個任務就建立一個線程,直到線程達到線程池的最大大小。
線程池的大小一旦達到最大值就會保持不變,若是某個線程由於執行異常而結束,那麼線程池會補充一個新線程。
new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
建立一個可緩存的線程池。若是線程池的大小超過了處理任務所須要的線程,
那麼就會回收部分空閒(60秒不執行任務)的線程,當任務數增長時,此線程池又能夠智能的添加新線程來處理任務。
此線程池不會對線程池大小作限制,線程池大小徹底依賴於操做系統(或者說JVM)可以建立的最大線程大小。
new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
轉載自:http://www.cnblogs.com/javanoob/p/threadpool.html