什麼是線程池
線程池就是裝有線程的池子,把要執行的線程交給線程池來處理,通過維護一定數量的線程池來達到多個線程的複用。
線程池的好處
如果不用線程池,每個線程都要通過new Thread(xxRunnable).start()的方法來創建並運行一個線程。每次創建一個和銷燬一個線程都是要消耗系統資源的。當線程數達到一定數量就會耗盡系統的CPU和內存資源,也會造成GC頻繁收集和停頓。而線程複用節省了很大的一部分系統資源,當線程一段時間不再有任務時自動銷燬,不會常駐內存。
線程池核心類
public ThreadPoolExecutor(int corePoolSize,//線程池的核心大小,也是最小的線程池大小
int maximumPoolSize,//最大線程池大小
long keepAliveTime,//空餘線程存活時間,指的是超過corePoolSize大小的空餘線程多長時間後銷燬
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;
}
線程池工作流程
- 如果線程池中的線程小於corePoolSize,創建新線程執行任務
- 如果線程池中的線程大於corePoolSize,把任務存儲到工作隊列workQueue中等待執行
- 如果workQueue也滿了,線程數小於maximumPoolSize就創建新線程執行任務;線程數大於等於maximumPoolSize就執行拒絕策略
線程池分類
Executors是JDK提供的創建線程池的工廠類
- newFixedThreadPool
固定線程池,核心線程數和最大線程固定相等,空閒存活時間爲0,工作隊列是最大爲Integer.MAX_VALUE大小的阻塞隊列。執行任務時,如果線程都很忙,就會等到工作隊列有空閒線程時再執行,隊列滿了就執行默認的拒絕策略。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
- newCachedThreadPool
帶緩衝線程池,核心線程數爲0,最大線程數爲Integer最大值大小,超過0個的空閒線程在60秒後銷燬。SynchronousQueue這是一個直接提交的隊列,每個新任務都會有線程來執行。如果線程池有可用線程則執行任務,沒有就創建一個來執行。線程池中的線程數不確定。一般建議執行速度較快較小的線程,不然這個最大線程池邊界過大容易造成內存溢出。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
- newSingleThreadExecutor
單線程線程池,核心線程數和最大線程數均爲1,空閒線程存活0毫秒。每次只執行一個線程,多餘的先存儲到工作隊列,一個一個執行,保證了線程的順序執行。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
- newScheduledThreadPool
調度線程池,即按一定的週期執行任務,即定時任務,對ThreadPoolExecutor進行了包裝。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
拒絕策略
- AbortPolicy
直接拋出拒絕異常,這也是默認的拒絕策略。
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }
/**
* Always throws RejectedExecutionException.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
- CallerRunsPolicy
如果線程池未關閉,則會在調用者線程中直接執行新任務,導致主線程提交線程性能變慢。
public static class CallerRunsPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code CallerRunsPolicy}.
*/
public CallerRunsPolicy() { }
/**
* Executes task r in the caller's thread, unless the executor
* has been shut down, in which case the task is discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
- DiscardPolicy
不處理新任務,丟棄。
public static class DiscardPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardPolicy}.
*/
public DiscardPolicy() { }
/**
* Does nothing, which has the effect of discarding task r.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
- DiscardOldestPolicy
拋棄最老的任務執行新任務
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardOldestPolicy} for the given executor.
*/
public DiscardOldestPolicy() { }
/**
* Obtains and ignores the next task that the executor
* would otherwise execute, if one is immediately available,
* and then retries execution of task r, unless the executor
* is shut down, in which case task r is instead discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
提交線程
ExecutorService es = Executors.newFixedThreadPool(3);//定義一個固定大小的線程池
es.submit(xxRunnble);//提交線程,execute沒有返回值,不知道線程結果
es.execute(xxRunnble);//提交線程,submit返回一個Future對象,並能在主線程中通過Future的get方法捕獲線程中的異常
關閉線程池
es.shutdown();//不再接受新的任務,等執行完所有任務後關閉線程池。
es.shutdownNow();//不再接受新的任務,嘗試停止所有任務後關閉線程池,返回未處理的線程list列表。