在SpringBoot中提供了異步任務的功能特性。
1.引入spring-boot-starter-web依賴
2.在Application啓動類上標註@EnableAsync註解
3.編寫異步方法:
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/**
* 異步處理服務
*/
@Slf4j
@Service
public class AsyncService {
@Async("getAsyncExecutor")
public void asyncProcess() throws InterruptedException {
log.info("async process task, current thread name -> {}",
Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(2);
}
@Async("getAsyncExecutor")
public Future<Integer> asyncProcessHasReturn() throws InterruptedException {
log.info("async process task (has return), current thread name -> {}",
Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(2);
return new AsyncResult<>(100);
}
}
此異步任務服務中定義了一個無返回值的異步方法,一個有返回值的方法。異步任務方法上須標註@Async註解,通過@Async指定使用的異步線程池。
4.自定義異步線程池
默認情況下,springboot異步線程池特別簡單,使得線程不能被重新利用。每次調用方法時都會重新創建線程。
因此需要對異步線程池做自定義配置:
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
/**
* <h1>自定義異步線程池的配置</h1>
*/
@Slf4j
@Configuration
public class AsyncPoolConfig implements AsyncConfigurer {
}
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* <h1>自定義異步線程池的配置</h1>
* 使用@Configuration標註配置類
* 須繼承AsyncConfigurer接口
*/
@Slf4j
@Configuration
public class AsyncPoolConfig implements AsyncConfigurer {
/**
* 獲取自定義的ThreadPoolExcutor
* 使用@Bean將其注入spring容器中
* */
@Bean
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);//線程池核心線程的數量
executor.setMaxPoolSize(20);//線程池維護線程的最大數量
executor.setQueueCapacity(20);//緩衝隊列任務的個數
executor.setKeepAliveSeconds(60);//超出核心線程數的線程最大存活時間
executor.setThreadNamePrefix("ImoocAsync_");
executor.setWaitForTasksToCompleteOnShutdown(true);//是否等待所有線程執行完畢後才關閉線程池
executor.setAwaitTerminationSeconds(60);//要關閉的等待時長,與上句一起生效
// 拒絕策略
executor.setRejectedExecutionHandler(
new ThreadPoolExecutor.AbortPolicy()
);
executor.initialize();
return executor;
}
/**
* <h2>定義異步任務異常處理類</h2>
* 返回自定義的AsyncExceptionHandler對象用作異常處理器
* */
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncExceptionHandler();
}
/**
* 自定義異常處理器 包含異常處理邏輯
*/
class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable throwable,
Method method, Object... objects) {
log.info("AsyncError: {}, Method: {}, Param: {}",
throwable.getMessage(),
method.getName(),
JSON.toJSONString(objects));
throwable.printStackTrace();
// TODO 發送郵件或者短信
}
}
}