• Spring Boot 中的异步调用


    通常我们开发的程序都是同步调用的,即程序按照代码的顺序一行一行的逐步往下执行,每一行代码都必须等待上一行代码执行完毕才能开始执行。而异步编程则没有这个限制,代码的调用不再是阻塞的。所以在一些情景下,通过异步编程可以提高效率,提升接口的吞吐量。这节将介绍如何在Spring Boot中进行异步编程。
    要开启异步支持,首先得在Spring Boot入口类上加上@EnableAsync注解:

    1. @SpringBootApplication
    2. @EnableAsync
    3. public class DemoApplication {
    4. public static void main(String[] args) {
    5. SpringApplication.run(DemoApplication.class, args);
    6. }
    7. }

    新建service包,并创建TestService:

    1. @Service
    2. public class TestService {
    3. private Logger logger = LoggerFactory.getLogger(this.getClass());
    4. @Async
    5. public void asyncMethod() {
    6. sleep();
    7. logger.info("异步方法内部线程名称:{}", Thread.currentThread().getName());
    8. }
    9. public void syncMethod() {
    10. sleep();
    11. }
    12. private void sleep() {
    13. try {
    14. TimeUnit.SECONDS.sleep(2);
    15. } catch (InterruptedException e) {
    16. e.printStackTrace();
    17. }
    18. }
    19. }

    上面的Service中包含一个异步方法asyncMethod(开启异步支持后,只需要在方法上加上@Async注解便是异步方法了)和同步方法syncMethod。sleep方法用于让当前线程阻塞2秒钟。
    因为异步的原因,程序并没有被sleep方法阻塞,这就是异步调用的好处。同时异步方法内部会新启一个线程来执行
    默认情况下的异步线程池配置使得线程不能被重用,每次调用异步方法都会新建一个线程,我们可以自己定义异步线程池来优化。
     

    1. @Configuration
    2. public class AsyncPoolConfig {
    3. @Bean
    4. public ThreadPoolTaskExecutor asyncThreadPoolTaskExecutor(){
    5. ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    6. executor.setCorePoolSize(20);
    7. executor.setMaxPoolSize(200);
    8. executor.setQueueCapacity(25);
    9. executor.setKeepAliveSeconds(200);
    10. executor.setThreadNamePrefix("asyncThread");
    11. executor.setWaitForTasksToCompleteOnShutdown(true);
    12. executor.setAwaitTerminationSeconds(60);
    13. executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
    14. executor.initialize();
    15. return executor;
    16. }
    17. }

    要使用该线程池,只需要在@Async注解上指定线程池Bean名称即可:

    1. @Service
    2. public class TestService {
    3. ......
    4. @Async("asyncThreadPoolTaskExecutor")
    5. public void asyncMethod() {
    6. ......
    7. }
    8. ......
    9. }

    处理异步回调

    如果异步方法具有返回值的话,需要使用Future来接收回调值。我们修改TestService的asyncMethod方法,给其添加返回值:

    1. @Async("asyncThreadPoolTaskExecutor")
    2. public Future<String> asyncMethod() {
    3. sleep();
    4. logger.info("异步方法内部线程名称:{}", Thread.currentThread().getName());
    5. return new AsyncResult<>("hello async");
    6. }

    Future接口的get方法用于获取异步调用的返回值。
    通过返回结果我们可以看出Future的get方法为阻塞方法,只有当异步方法返回内容了,程序才会继续往下执行。get还有一个get(long timeout, TimeUnit unit)重载方法,我们可以通过这个重载方法设置超时时间,即异步方法在设定时间内没有返回值的话,直接抛出java.util.concurrent.TimeoutException异常。
    比如设置超时时间为60秒:
     

  • 相关阅读:
    app测试和web测试有什么区别
    Codeforces Round 734
    Educational Codeforces Round 133 (Rated for Div. 2)
    关于论青少年尽早学少儿编程之说
    【艾特淘】天猫家饰商家必看:金九银十运营策略
    RabbitMq安装过程
    Greenplum实用工具-gpfdist
    第一章:最新版零基础学习 PYTHON 教程(第十八节 - Python 表达式语句–Python导入语句)
    Mongodb7 分片集群的搭建
    k8s使用nfs配置StorageClass,配置完成后,创建pvc一直为pending的状态。
  • 原文地址:https://blog.csdn.net/weixin_44545895/article/details/126013036