首先咱們先看一下獲取四種線程池的代碼:html
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10); ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10); ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
能夠發現這四種線程池都是由Executors類生成的。依次點開四個方法的內部實現發現,它們最終調用的都是同一個ThreadPoolExecutor()的構造器,而區別在於構造器的參數不一樣。咱們來看下ThreadPoolExecutor的參數列表:併發
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
正是因爲這幾個參數的不一樣致使了四種線程池的工做機制不一樣。參考源碼對於參數的註釋,咱們列出參數的含義。線程
handler:當等待隊列容量滿以及線程池數量達到最大時,如何處理新的任務。code
當持續往線程池添加任務,
當前線程數量小於核心線程數量的時候,新增線程。
當前線程數量達到核心線程數量的時候,將任務放入等待隊列。
當等待隊列滿的時候,繼續建立新線程。
當線程池數量達到最大而且等待隊列也滿的時候,採起拒絕服務策略。htm
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
咱們能夠看到corePoolSize核心線程數量和maximumPoolSize最大線程數量是一致的,而且keepAliveTime爲0。workQueue是LinkedBlockingQueue,這是一個鏈表阻塞隊列。能夠得出結論:該線程池是一個固定數量的線程池,而且有一個無界的等待隊列。咱們能夠推導出該線程池適合處理任務量平穩的場景。例如平均一秒接收10個任務,接收任務量曲線不會很陡峭。排序
適合場景:適合少許的大任務(大任務處理慢,若是線程數量多的話,反而在切換線程上下文時損耗,因此控制線程在必定的數量)。隊列
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
咱們能夠看到corePoolSize核心線程池爲0,表明該線程沒有核心線程池,意味着線程都是可被回收銷燬的,線程池中有時會是空的。而且maximumPoolSize是int最大值,至關於表明該線程池能夠無限建立線程。keepAliveTime爲60,表明空閒60秒回收線程。workQueue是SynchronousQueue,該同步隊列是一個沒有容量隊列,即一個任務到來後,要等待線程來消費,才能再繼續添加任務。咱們推導出該線程池適合處理平時沒什麼任務量,但有時任務量瞬間劇增的場景。get
適合場景:大量的小任務(每一個任務處理快,不會頻繁出現線程處理一半時,切換其餘線程)。同步
public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue()); }
咱們能夠看到該線程池參數最大的區別在於workQueue是DelayedWorkQueue。該隊列是一個按延遲時間從小到大排序的堆。而且當隊列頭節點的延遲時間小於0的時候返回該節點。因此該線程池能夠指定一個時間進行定時任務。也能夠經過添加任務時遞增延遲時間,來進行週期任務。源碼
適合場景:定時任務或者週期任務。
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
咱們能夠看到該線程池的corePoolSize核心線程數量和maximumPoolSize最大線程數量都是1,表明該線程有且只有一個固定的線程,既然是單線程,因此該線程池實現的是串行操做,沒有併發效果。workQueue是LinkedBlockingQueue,這是一個鏈表阻塞隊列。因此該線程池適合執行串行執行隊列中的任務。
適合場景:按順序串行處理的任務。
keepAliveTime參數註釋明確指明只對非核心線程有用。
咱們能夠從ScheduledThreadPool的源碼中推測,若是0表明是永不回收的話,那麼ScheduledThreadPool一旦建立出非核心線程的話就不會回收了?這樣是很不合理的。因此筆者認爲0表明當即回收。
public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue()); }