1. 開啟非同步
@SpringBootApplication
@EnableAsync //開啟非同步任務
public class Application {
@Bean(name="processExecutor")
public TaskExecutor workExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setThreadNamePrefix("Async-");
threadPoolTaskExecutor.setCorePoolSize(10);
threadPoolTaskExecutor.setMaxPoolSize(20);
threadPoolTaskExecutor.setQueueCapacity(600);
threadPoolTaskExecutor.afterPropertiesSet();
// 自定義拒絕策略
threadPoolTaskExecutor.setRejectedExecutionHandler((r, executor) -> {
// .....
});
// 使用預設的拒絕策略
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return threadPoolTaskExecutor;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
複製程式碼
2. 配置執行緒池
Spring非同步執行緒池的介面類,其實質是java.util.concurrent.Executor。
Spring 已經實現的異常執行緒池:
- SimpleAsyncTaskExecutor:
不是真的執行緒池,這個類不重用執行緒,每次呼叫都會建立一個新的執行緒。 - SyncTaskExecutor:
這個類沒有實現非同步呼叫,只是一個同步操作。只適用於不需要多執行緒的地方 - ConcurrentTaskExecutor:
Executor的適配類,不推薦使用。如果ThreadPoolTaskExecutor不滿足要求時,才用考慮使用這個類 - SimpleThreadPoolTaskExecutor:
是Quartz的SimpleThreadPool的類。執行緒池同時被quartz和非quartz使用,才需要使用此類 - ThreadPoolTaskExecutor:
最常使用,推薦。其實質是對java.util.concurrent.ThreadPoolExecutor的包裝。
3. 新增@Async註解
/**
* 非同步呼叫返回Future
*
* @param i
* @return
*/
@Async
public Future<String> asyncInvokeReturnFuture(int i) {
log.info("asyncInvokeReturnFuture, parementer={}", i);
Future<String> future;
try {
Thread.sleep(1000 * 1);
future = new AsyncResult<String>("success:" + i);
} catch (InterruptedException e) {
future = new AsyncResult<String>("error");
}
return future;
}
複製程式碼
4. 通過XML檔案配置
<!-- 等價於 @EnableAsync, executor指定執行緒池 -->
<task:annotation-driven executor="xmlExecutor"/>
<!-- id指定執行緒池產生執行緒名稱的字首 -->
<task:executor
id="xmlExecutor"
pool-size="5-25"
queue-capacity="100"
keep-alive="120"
rejection-policy="CALLER_RUNS"/>
複製程式碼
5. 異常處理
在呼叫方法時,可能出現方法中丟擲異常的情況。在非同步中主要有有兩種異常處理方法:
- 對於方法返回值是Futrue的非同步方法:
a) 一種是在呼叫future的get時捕獲異常;
b) 在異常方法中直接捕獲異常 - 對於返回值是void的非同步方法:
通過AsyncUncaughtExceptionHandler處理異常
/**
* 通過實現AsyncConfigurer自定義執行緒池,包含異常處理
*
*/
@Service
public class MyAsyncConfigurer implements AsyncConfigurer{
private static final Logger log = LoggerFactory.getLogger(MyAsyncConfigurer.class);
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
threadPool.setCorePoolSize(1);
threadPool.setMaxPoolSize(1);
threadPool.setWaitForTasksToCompleteOnShutdown(true);
threadPool.setAwaitTerminationSeconds(60 * 15);
threadPool.setThreadNamePrefix("MyAsync-");
threadPool.initialize();
return threadPool;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new MyAsyncExceptionHandler();
}
/**
* 自定義異常處理類
*/
class MyAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
log.info("Exception message - " + throwable.getMessage());
log.info("Method name - " + method.getName());
for (Object param : obj) {
log.info("Parameter value - " + param);
}
}
}
}
複製程式碼