一、Executor架構簡介
1、基礎簡介
Executor系統中,将線程任務送出和任務執行進行了解耦的設計,Executor有各種功能強大的實作類,提供便捷方式來送出任務并且擷取任務執行結果,封裝了任務執行的過程,不再需要Thread().start()方式,顯式建立線程并關聯執行任務。
2、排程模型
線程被一對一映射為服務所在作業系統線程,啟動時會建立一個作業系統線程;當該線程終止時,這個作業系統線程也會被回收。

3、核心API結構
Executor架構包含的核心接口和主要的實作類如下圖所示:
線程池任務:核心接口:Runnable、Callable接口和接口實作類;
任務的結果:接口Future和實作類FutureTask;
任務的執行:核心接口Executor和ExecutorService接口。在Executor架構中有兩個核心類實作了ExecutorService接口,ThreadPoolExecutor和ScheduledThreadPoolExecutor。
二、用法案例
1、API基礎
ThreadPoolExecutor基礎構造
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {}
2、初始化方法
ExecutorService :Executors.newFixedThreadPool();
ExecutorService :Executors.newSingleThreadExecutor();
ExecutorService :Executors.newCachedThreadPool();
ThreadPoolExecutor :new ThreadPoolExecutor() ;
通常情況下,線程池不允許使用Executors去建立,而是通過ThreadPoolExecutor的方式,這樣的處理方式更加明确線程池的運作規則,規避資源耗盡的風險。
3、基礎案例
package com.multy.thread.block08executor;
import java.util.concurrent.*;
public class Executor01 {
// 定義線程池
private static ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
3,10,5000,TimeUnit.SECONDS,
new SynchronousQueue<>(),Executors.defaultThreadFactory(),new ExeHandler());
public static void main(String[] args) {
for (int i = 0 ; i < 100 ; i++){
poolExecutor.execute(new PoolTask(i));
//帶傳回值:poolExecutor.submit(new PoolTask(i));
}
}
}
// 定義線程池任務
class PoolTask implements Runnable {
private int numParam;
public PoolTask (int numParam) {
this.numParam = numParam;
}
@Override
public void run() {
try {
System.out.println("PoolTask "+ numParam+" begin...");
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
}
public int getNumParam() {
return numParam;
}
public void setNumParam(int numParam) {
this.numParam = numParam;
}
}
// 定義異常處理
class ExeHandler implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable runnable, ThreadPoolExecutor executor) {
System.out.println("ExeHandler "+executor.getCorePoolSize());
executor.shutdown();
}
}
流程分析
- 線程池中線程數小于corePoolSize時,新任務将建立一個新線程執行任務,不論此時線程池中存在空閑線程;
- 線程池中線程數達到corePoolSize時,新任務将被放入workQueue中,等待線程池中任務排程執行;
- 當workQueue已滿,且maximumPoolSize>corePoolSize時,新任務會建立新線程執行任務;
- 當workQueue已滿,且送出任務數超過maximumPoolSize,任務由RejectedExecutionHandler處理;
- 當線程池中線程數超過corePoolSize,且超過這部分的空閑時間達到keepAliveTime時,回收該線程;
- 如果設定allowCoreThreadTimeOut(true)時,線程池中corePoolSize範圍内的線程空閑時間達到keepAliveTime也将回收;
三、線程池應用
應用場景:批量賬戶和密碼的校驗任務,在實際的業務中算比較常見的,通過初始化線程池,把任務送出執行,最後拿到處理結果,這就是線程池使用的核心思想:節省資源提升效率。
public class Executor02 {
public static void main(String[] args) {
// 初始化校驗任務
List<CheckTask> checkTaskList = new ArrayList<>() ;
initList(checkTaskList);
// 定義線程池
ExecutorService executorService ;
if (checkTaskList.size() < 10){
executorService = Executors.newFixedThreadPool(checkTaskList.size());
}else{
executorService = Executors.newFixedThreadPool(10);
}
// 批量處理
List<Future<Boolean>> results = new ArrayList<>() ;
try {
results = executorService.invokeAll(checkTaskList);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 檢視結果
for (Future<Boolean> result : results){
try {
System.out.println(result.get());
// System.out.println(result.get(10000,TimeUnit.SECONDS));
} catch (Exception e) {
e.printStackTrace() ;
}
}
// 關閉線程池
executorService.shutdownNow();
}
private static void initList (List<CheckTask> checkTaskList){
checkTaskList.add(new CheckTask("root","123")) ;
checkTaskList.add(new CheckTask("root1","1234")) ;
checkTaskList.add(new CheckTask("root2","1235")) ;
}
}
// 校驗任務
class CheckTask implements Callable<Boolean> {
private String userName ;
private String passWord ;
public CheckTask(String userName, String passWord) {
this.userName = userName;
this.passWord = passWord;
}
@Override
public Boolean call() throws Exception {
// 校驗賬戶+密碼
if (userName.equals("root") && passWord.equals("123")){
return Boolean.TRUE ;
}
return Boolean.FALSE ;
}
}
線程池主要用來解決線程生命周期開銷問題和資源不足問題,通過線程池對多個任務線程重複使用,線程建立也被分攤到多個任務上,多數任務送出就有空閑的線程可以使用,是以消除線程頻繁建立帶來的開銷。
四、源代碼位址
GitHub·位址
https://github.com/cicadasmile/java-base-parent
GitEE·位址
https://gitee.com/cicadasmile/java-base-parent