何为异步
需要区分的是同步就是顺序执行,等一次调用返回结果才会执行下一次调用,如果调用出现迟缓,程序也会出现迟缓
异步则只是发送了调用的命令,然后不再等待调用结果继续向下执行,减少迟缓
异步(注解方式)
在Spring中,基于@Async标注的方法,称之为异步方法;这些方法将在执行的时候,将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作
在spring3后提供注解支持,内置了@Async注解完成异步任务
- @EnableAsync: 用在主配置类上,支持异步
- @Async:放在需要异步执行的方法上
@SpringBootApplication
@EnableAsync
public class AsyncApplication {
public static void main(String[] args) {
SpringApplication.run(AsyncApplication.class, args);
}
}
@Async
public void say() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("异步执行");
}
在测试时发现并没有在主配置类上添加支持也可以
注意事项
@Async 默认每次调用都创建新线程,生产环境一定要配线程池,否则线程会越开越多
@Configuration
public class AsyncConfig implements AsyncConfigurer {
@Bean("taskExecutor")
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("async-");
executor.setRejectedExecutionHandler(
new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
然后指定线程池名:
@Async("taskExecutor")
public void sendNotification(String phone, String content) { ... }
@Async 方法不能在本类的另一个方法里直接调用——因为 Spring 的 AOP 代理只能拦截从外部调用的方法。如果 sendNotification 和调用它的方法在同一个类里,@Async 不会生效
返回值
如果方法需要返回结果,用 Future<T> 或 CompletableFuture<T>
@Async
public CompletableFuture<String> sendWithResult(String phone, String content) {
// ...
return CompletableFuture.completedFuture("发送成功");
}
重要:返回 void 的 @Async 方法,内部异常会被 Spring 静默吞掉——只打一行日志,不会抛给调用方,你甚至感知不到短信没发出去。生产环境务必配置 AsyncUncaughtExceptionHandler,把异常打到监控系统
@Configuration
public class AsyncConfig implements AsyncConfigurer {
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (Throwable ex, Method method, Object... params) -> {
// 接入监控告警,不要只打日志
log.error("[Async异常] 方法: {} | 参数: {}", method.getName(), params, ex);
};
}
}