参考https://blog.csdn.net/m0_65992672/article/details/130422166
@SpringBootApplication
@EnableAsync//开启异步任务支持
public class ApplicationStarter {
public static void main(String[] args) {
SpringApplication.run(ApplicationStarter.class,args);
}
}
@Service
public class AsyncServiceImpl implements AsyncService {
//使用@Async注解标记的方法 会提交到一个异步任务中进行执行,第一次不会执行该方法,
//如果不添加该注解,controller中调用该方法会等待5秒在响应
//异步任务
@Async
public void t1() {
// 模拟耗时任务
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(5));
} catch (InterruptedException e) {
e.printStackTrace();
}
//因为该异步方法中使用了休眠,所以过5秒才会执行下面代码
System.out.println("异步方法中:耗时时间已走完");
}
@Async
public Future<String> t2(){
// 模拟耗时任务
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(5));
} catch (InterruptedException e) {
e.printStackTrace();
}
return new AsyncResult<>("async tasks done!");
}
}
3、异步任务相关限制
被@Async注解的异步任务方法存在相关限制:
被@Async注解的方法必须是public的,这样方法才可以被代理。
不能在同一个类中调用@Async方法,因为同一个类中调用会绕过方法代理,调用的是实际的方法。
被@Async注解的方法不能是static。
@Async注解不能与 Bean 对象的生命周期回调函数(比如@PostConstruct)一起注解到同一个方法中。解决方法可参考:Spring - The @Async annotation
异步类必须注入到 Spring IOC 容器中(也即异步类必须被@Component/@Service等进行注解)。
其他类中使用异步类对象必须通过@Autowired等方式进行注入,不能手动new对象。
4、自定义 Executor(自定义线程池)
默认情况下,Spring 会自动搜索相关线程池定义:要么是一个唯一TaskExecutor Bean 实例,要么是一个名称为taskExecutor的Executor Bean 实例。如果这两个 Bean 实例都不存在,就会使用SimpleAsyncTaskExecutor来异步执行被@Async注解的方法。
综上,可以知道,默认情况下,Spring 使用的 Executor 是SimpleAsyncTaskExecutor,SimpleAsyncTaskExecutor每次调用都会创建一个新的线程,不会重用之前的线程。很多时候,这种实现方式不符合我们的业务场景,因此通常我们都会自定义一个 Executor 来替换SimpleAsyncTaskExecutor。
对于自定义 Executor(自定义线程池),可以分为如下两个层级:
应用层级:即全局生效的 Executor。依据 Spring 默认搜索机制,其实就是配置一个全局唯一的TaskExecutor实例或者一个名称为taskExecutor的Executor实例即可,如下所示:
方法层级:即为单独一个或多个方法指定运行线程池,其他未指定的异步方法运行在默认线程池。如下所示: