异步编程也就是多线程编程,springboot 提供了简单的多线程实现
jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
@EnableAsync 在Springboot01Application入口类上
@SpringBootApplication
@EnableAsync
public class Springboot01Application {
public static void main(String[] args) {
SpringApplication.run(Springboot01Application.class, args);
}
}
编写异步任务
@Component
@Slf4j
public class AsyncTest {
@Async
public void async01() throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
log.info(Thread.currentThread().getName()+",执行了");
// 没有返回值得异步编程,全局处理器无法捕捉到,需要单独处理
throw new RuntimeException("人为异常");
}
@Async
public Future<String> async02() throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
log.info("有返回值的线程名称为:{}",Thread.currentThread().getName());
//文件上传。。。。文件路径
//有返回值得异步编程,全局处理器可以捕捉到
throw new RuntimeException("人为异常");
// return new AsyncResult<>("异步任务的返回值");
}
}
测试
@RestController
@Slf4j
public class Test01 {
// 异步编程
@Autowired
private AsyncTest asyncTest;
@GetMapping("/async01")
public void async01() throws InterruptedException {
asyncTest.async01();
}
@GetMapping("/async02")
public String async02() throws InterruptedException, ExecutionException {
Future<String> stringFuture = asyncTest.async02();
return stringFuture.get();
}
}
自定义线程池
不使用springboot提供的线程池,选择自定义
@Configuration
@Slf4j
public class AsyncPoolConfig implements AsyncConfigurer {
@Override
@Bean
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(5);
threadPoolTaskExecutor.setMaxPoolSize(10);
threadPoolTaskExecutor.setKeepAliveSeconds(10);
threadPoolTaskExecutor.setQueueCapacity(100);
threadPoolTaskExecutor.setThreadNamePrefix("XXXX-");//线程名字前缀
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return threadPoolTaskExecutor;
}
}
全局异常处理器
可以捕获有返回值的异步编程异常
@RestControllerAdvice
@Slf4j
public class MyExceptionHandler {
@ExceptionHandler(Exception.class)
public Map<String,String> map(Exception e){
HashMap<String, String> map = new HashMap<>();
map.put("异常",e.getMessage());
return map;
}
}
单独处理线程异常
因为无返回值异步编程得异常无法被全局异常处理器捕捉到,因此需要单独处理,在自定义线程池类中重写getAsyncUncaughtExceptionHandler方法即可!
@Configuration
@Slf4j
public class AsyncPoolConfig implements AsyncConfigurer {
@Override
@Bean
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
// 最好在配置文件中设置
threadPoolTaskExecutor.setCorePoolSize(5);
threadPoolTaskExecutor.setMaxPoolSize(10);
threadPoolTaskExecutor.setKeepAliveSeconds(10);
threadPoolTaskExecutor.setQueueCapacity(100);
threadPoolTaskExecutor.setThreadNamePrefix("xxxx-");//线程名字前缀
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return threadPoolTaskExecutor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
// 返回值是一个接口,需要实现类,这里用lamda
return (Throwable var1, Method var2, Object... var3)->{log.info("捕获无返回值得异步编程异常");};
}
}