• 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秒:
     

  • 相关阅读:
    综合案例-数据可视化-柱状图
    2024前端面试题之Vue3
    macOS磁盘分区调整软件--Paragon Camptune X 中文
    聚观早报 | 智界S7正式亮相;ChatGPT重磅更新
    Python数据分析----Numpy介绍与安装
    RoaringBitMap学习和实践
    【面向对象程序设计】Java大作业 汽车租赁管理系统V4.0
    如何查看postgresql中的数据库大小?
    pytorch单机多卡及常见问题
    leecode#用Read4读取n个字符#相交链表
  • 原文地址:https://blog.csdn.net/weixin_44545895/article/details/126013036