BlockingQueue<Runnable> workQueue = null;
workQueue = new ArrayBlockingQueue<>(5);//基於數組的先進先出隊列,有界
workQueue = new LinkedBlockingQueue<>();//基於鏈表的先進先出隊列,無界
workQueue = new SynchronousQueue<>();//無緩衝的等待隊列,無界html
RejectedExecutionHandler rejected = null;
rejected = new ThreadPoolExecutor.AbortPolicy();//默認,隊列滿了丟任務拋出異常
rejected = new ThreadPoolExecutor.DiscardPolicy();//隊列滿了丟任務不異常
rejected = new ThreadPoolExecutor.DiscardOldestPolicy();//將最先進入隊列的任務刪,以後再嘗試加入隊列
rejected = new ThreadPoolExecutor.CallerRunsPolicy();//若是添加到線程池失敗,那麼主線程會本身去執行該任務java
ExecutorService threadPool = null;
threadPool = Executors.newCachedThreadPool();//有緩衝的線程池,線程數 JVM 控制
threadPool = Executors.newFixedThreadPool(3);//固定大小的線程池
threadPool = Executors.newScheduledThreadPool(2);
threadPool = Executors.newSingleThreadExecutor();//單線程的線程池,只有一個線程在工做
threadPool = new ThreadPoolExecutor();//默認線程池,可控制參數比較多數組
很簡單,簡單看名字就知道是裝有線程的池子,咱們能夠把要執行的多線程交給線程池來處理,和鏈接池的概念同樣,經過維護必定數量的線程池來達到多個線程的複用。
安全
咱們知道不用線程池的話,每一個線程都要經過new Thread(xxRunnable).start()的方式來建立並運行一個線程,線程少的話這不會是問題,而真實環境可能會開啓多個線程讓系統和程序達到最佳效率,當線程數達到必定數量就會耗盡系統的CPU和內存資源,也會形成GC頻繁收集和停頓,由於每次建立和銷燬一個線程都是要消耗系統資源的,若是爲每一個任務都建立線程這無疑是一個很大的性能瓶頸
。因此,線程池中的線程複用極大節省了系統資源,當線程一段時間再也不有任務處理時它也會自動銷燬,而不會長駐內存。多線程
在java.util.concurrent包中咱們能找到線程池的定義,其中ThreadPoolExecutor
是咱們線程池核心類,首先看看線程池類的主要參數有哪些。併發
/** * Creates a new {@code ThreadPoolExecutor} with the given initial * parameters and default thread factory. */ public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
Executors
是jdk裏面提供的建立線程池的工廠類,它默認提供了4種經常使用的線程池應用,而沒必要咱們去重複構造。async
newFixedThreadPool
/** * Creates a thread pool that reuses a fixed number of threads * operating off a shared unbounded queue, using the provided * ThreadFactory to create new threads when needed. */ public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory); }
newCachedThreadPool
/** * Creates a thread pool that creates new threads as needed, but * will reuse previously constructed threads when they are * available. These pools will typically improve the performance * of programs that execute many short-lived asynchronous tasks. */ public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
newSingleThreadExecutor
/** * Creates an Executor that uses a single worker thread operating * off an unbounded queue. (Note however that if this single * thread terminates due to a failure during execution prior to * shutdown, a new one will take its place if needed to execute * subsequent tasks.) Tasks are guaranteed to execute * sequentially, and no more than one task will be active at any * given time. Unlike the otherwise equivalent */ public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
newScheduledThreadPool
/** * Creates a thread pool that can schedule commands to run after a * given delay, or to execute periodically. */ public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); }
緩衝隊列BlockingQueue簡介:ide
BlockingQueue是雙緩衝隊列。BlockingQueue內部使用兩條隊列,容許兩個線程同時向隊列一個存儲,一個取出操做。在保證併發安全的同時,提升了隊列的存取效率。
能夠先隨便定義一個固定大小的線程池函數
ExecutorService es = Executors.newFixedThreadPool(3);
提交一個線程性能
es.submit(xxRunnble); es.execute(xxRunnble);
submit和execute分別有什麼區別呢?
咱們來看看execute()到底方法是如何處理的:
es.shutdown();
再也不接受新的任務,以前提交的任務等執行結束再關閉線程池。
es.shutdownNow();
再也不接受新的任務,試圖中止池中的任務再關閉線程池,返回全部未處理的線程list列表。
線程池主要用來解決線程生命週期開銷問題和資源不足問題。經過對多個任務重複使用線程,線程建立的開銷就被分攤到多個任務上,並且因爲在請求到達時線程已經存在,因此消除線程建立所帶來的延遲。這樣,就能夠當即爲請求服務,使應用程序響應更快。另外,經過適當的調整線程中的線程數目能夠防止出現資源不足。