Java線程池--ThreadPoolExecutor學習記錄
簡介
線程池的使用是爲了減少頻繁創建線程帶來的資源開銷,統一管理線程。其中核心線程工具類ThreadPoolExecutor
在多線程當中發揮至關重要的作用。
ThreadPoolExecutor關鍵父類
1、頂層接口Executor,只提供了void execute(Runnable command)方法執行當前線程
2、第二層接口ExecutorService繼承Executor接口,並擴展了一些方法,包括線程終止、提交等等void shutdown()、List<Runnable> shutdownNow()、boolean isShutdown()、 boolean isTerminated()、boolean awaitTermination(long timeout, TimeUnit unit)、<T> Future<T> submit(Callable<T> task)等等
3、第三層抽象類AbstractExecutorService實現ExecutorService接口,並新增了一些方法,包括<T> RunnableFuture<T> newTaskFor(Runnable runnable, T value)、<T> RunnableFuture<T> newTaskFor(Callable<T> callable)等等
4、第四層ThreadPoolExecutor繼承AbstractExecutorService類,對線程池真正的操作都在這個核心線程池工具類中,包括創建不同的線程池類型、獲取線程池中各個參數、線程池的拒絕策略等等
ThreadPoolExecutor四種構造函數
1、 第一個參數是核心線程池的大小、第二個是最大線程池大小、第三個參數空閒線程存活時間、第四個是時間單位、第五個是緩衝隊列,默認調用本地的構造方法使用默認線程工廠和默認的拒絕策略(AbortPolicy-拋出異常)
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
2、 同理,只是指定了創建線程的工廠接口不使用默認的,其他同第一個
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
3、同理,指定了線程拒絕策略,其他同第一個
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
4、同理,指定全部的參數來構造線程池執行器
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.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
ThreadPoolExecutor構造函數參數說明
1、corePoolSize ---- 核心線程池個數
2、maximumPoolSize ---- 最大線程池個數
3、keepAliveTime ---- 超出核心線程數空閒線程存活時間(依賴第四個參數的值)
4、unit ---- 存活時間單位(毫秒、秒、分、時、天)
5、workQueue ---- 緩衝隊列(有界隊列ArrayBlockingQueue、無界隊列LinkedBlockingQueue(可以指定大小)\SynchronousQueue等等)
6、threadFactory ---- 創建線程的工具接口,有不同的工廠類實現該接口DefaultThreadFactory、 DaemonThreadFactory等等
7、handler ---- 當線程超出最大線程個數時執行的拒絕策略,主要有(AbortPolicy(默認)當線程超出後再有新的線程會拋出異常RejectedExecutionException,DiscardPolicy-直接丟棄沒有任何提示,
DiscardOldestPolicy-丟棄最久的線程,CallerRunsPolicy-拋給調用方自行處理)
corePoolSize和maximumPoolSize之間的關係:
1、當前線程小於corePoolSize時,有新的請求進來會立即啓動新線程來處理
2、當前線程大於corePoolSize小於maximumPoolSize,會加入緩衝隊列中等待
3、當前線程大於maximumPoolSize,有新的請求進來執行拒絕策略
4、當緩衝隊列已滿,且maximumPoolSize>corePoolSize時,新提交任務會創建新線程執行任務
ThreadPoolExecutor創建不同類型的線程池
1-單例線程池-創建固定線程池大小爲1
ExecutorService executor1 = Executors.newFixedThreadPool(1);
ThreadPoolExecutor executor2 = new ThreadPoolExecutor(
1, 1, 0L, TimeUnit.MILLISECONDS
,new LinkedBlockingQueue<>()
,Executors.defaultThreadFactory()
,new ThreadPoolExecutor.AbortPolicy());
2-固定線程池-創建10個固定線程池
ExecutorService executor1 = Executors.newFixedThreadPool(10);
ThreadPoolExecutor executor2 = new ThreadPoolExecutor(
10, 10, 0L, TimeUnit.MILLISECONDS
,new LinkedBlockingQueue<>()
,Executors.defaultThreadFactory()
,new ThreadPoolExecutor.AbortPolicy());
3-可複用線程池
ExecutorService executor1 = Executors.newCachedThreadPool();
ThreadPoolExecutor executor2 = new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
4-延遲線程池
ExecutorService executor1 = Executors.newScheduledThreadPool(1);
ThreadPoolExecutor executor2 = new ThreadPoolExecutor(1,
Integer.MAX_VALUE,
0L,NANOSECONDS,
new DelayedWorkQueue<Runnable>());