spring springboot关于异步线程实践案例

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: spring springboot关于异步线程实践案例
前言:

关于多线程的异步处理,由于项目的需求有个方法需要使用异步的方法来调用,方法是调用外部的接口,执行时间会比较长导致的没有办法同步拿去到结果,所以需要写一个异步线程的方法进行该接口的调用,下面是一个案例以及自己测试的异步结果的情况;

第一步:需要是项目启动的初始化启动异步的配置处理

第二步:需要创建config进行配置相关线程池的处理

@Configuration

public class SpringBootAsyncConfig {

   private static final Logger LOGGER = LoggerFactory.getLogger(SpringBootMvcConfig.class);

   @Value("${spring.async.thread.pool.core-pool-size}")

   private int corePoolSize = 10;

   @Value("${spring.async.thread.pool.max-pool-size}")

   private int maxPoolSize = 1000;

   @Value("${spring.async.thread.pool.queue-capacity}")

   private int queueCapacity = 1000;

   @Value("${spring.async.thread.pool.keep-alive-seconds}")

   private int keepAliveSeconds = 600;


   public SpringBootAsyncConfig() {

   }


   @Bean({"asyncThreadPool"})

   public TaskExecutor taskExecutor() {

       ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

       executor.setCorePoolSize(this.corePoolSize);

       executor.setMaxPoolSize(this.maxPoolSize);

       executor.setQueueCapacity(this.queueCapacity);

       executor.setKeepAliveSeconds(this.keepAliveSeconds);

       executor.setThreadNamePrefix("AsyncThreadPool-");

       executor.setRejectedExecutionHandler(new AbortPolicy());

       executor.setTaskDecorator(new TaskDecorator() {

           public Runnable decorate(Runnable runnable) {

               Map<String, Object> captureMapData = DataCaptureContext.getMapData();

               Map<String, String> mdcMap = MDC.getCopyOfContextMap();

               return () -> {

                   try {

                       if (mdcMap != null) {

                           MDC.setContextMap(mdcMap);

                       }


                       if (captureMapData != null) {

                           DataCaptureContext.setMapData(captureMapData);

                       }


                       runnable.run();

                   } finally {

                       MDC.clear();

                       DataCaptureContext.removeMapData();

                   }


               };

           }

       });

       executor.initialize();

       return executor;

   }


   @Bean({"springSessionRedisTaskExecutor"})

   public ThreadPoolTaskExecutor springSessionRedisTaskExecutor() {

       ThreadPoolTaskExecutor springSessionRedisTaskExecutor = new ThreadPoolTaskExecutor();

       springSessionRedisTaskExecutor.setCorePoolSize(10);

       springSessionRedisTaskExecutor.setMaxPoolSize(10);

       springSessionRedisTaskExecutor.setKeepAliveSeconds(600);

       springSessionRedisTaskExecutor.setQueueCapacity(1000);

       springSessionRedisTaskExecutor.setThreadNamePrefix("Spring session redis executor thread: ");

       springSessionRedisTaskExecutor.setRejectedExecutionHandler(new DiscardPolicy());

       springSessionRedisTaskExecutor.initialize();

       return springSessionRedisTaskExecutor;

   }


   @Bean({"bankInstructionTaskExecutor"})

   public ThreadPoolTaskExecutor bankInstructionTaskExecutor() {

       ThreadPoolTaskExecutor bankInstructionTaskExecutor = new ThreadPoolTaskExecutor();

       bankInstructionTaskExecutor.setCorePoolSize(20);

       bankInstructionTaskExecutor.setMaxPoolSize(20);

       bankInstructionTaskExecutor.setKeepAliveSeconds(1800);

       bankInstructionTaskExecutor.setQueueCapacity(20);

       bankInstructionTaskExecutor.setThreadNamePrefix("bank instruction task  executor thread: ");

       bankInstructionTaskExecutor.setRejectedExecutionHandler(new DiscardPolicy());

       bankInstructionTaskExecutor.setTaskDecorator(new TaskDecorator() {

           public Runnable decorate(Runnable runnable) {

               Map<String, Object> captureMapData = DataCaptureContext.getMapData();

               Map<String, String> mdcMap = MDC.getCopyOfContextMap();

               return () -> {

                   try {

                       if (mdcMap != null) {

                           MDC.setContextMap(mdcMap);

                       }


                       if (captureMapData != null) {

                           DataCaptureContext.setMapData(captureMapData);

                       }


                       runnable.run();

                   } finally {

                       MDC.clear();

                       DataCaptureContext.removeMapData();

                   }


               };

           }

       });

       bankInstructionTaskExecutor.initialize();

       return bankInstructionTaskExecutor;

   }


   @Bean({"instructionStatusUpdateTaskExecutor"})

   public ThreadPoolTaskExecutor instructionStatusUpdateTaskExecutor() {

       ThreadPoolTaskExecutor bankInstructionTaskExecutor = new ThreadPoolTaskExecutor();

       bankInstructionTaskExecutor.setCorePoolSize(20);

       bankInstructionTaskExecutor.setMaxPoolSize(20);

       bankInstructionTaskExecutor.setKeepAliveSeconds(1800);

       bankInstructionTaskExecutor.setQueueCapacity(20);

       bankInstructionTaskExecutor.setThreadNamePrefix("instruction status update executor thread: ");

       bankInstructionTaskExecutor.setRejectedExecutionHandler(new DiscardPolicy());

       bankInstructionTaskExecutor.setTaskDecorator(new TaskDecorator() {

           public Runnable decorate(Runnable runnable) {

               Map<String, Object> captureMapData = DataCaptureContext.getMapData();

               Map<String, String> mdcMap = MDC.getCopyOfContextMap();

               return () -> {

                   try {

                       if (mdcMap != null) {

                           MDC.setContextMap(mdcMap);

                       }


                       if (captureMapData != null) {

                           DataCaptureContext.setMapData(captureMapData);

                       }


                       runnable.run();

                   } finally {

                       MDC.clear();

                       DataCaptureContext.removeMapData();

                   }


               };

           }

       });

       bankInstructionTaskExecutor.initialize();

       return bankInstructionTaskExecutor;

   }

}

第三步:在调用异步方法的时候需要进行注解的标注该方法是异步的方法

第四步:异步方法的调用执行情况如下

第五步:异步方法的调用情况二

总结:

需要注意的点有三个,也就是分为三种情况:

  1. 避免同步方法里面调用异步的方法,比如说在controller里面的类直接调用本controller里面的异步方法,这个时候是不会产生异步的效果的,还是会顺序的执行。
  2. 如果说在controller里面调用service里面的同步方法的话,同步方法里面有调用其他的异步方法,这个时候也会认为是同步的方法,也会顺序的执行,异步没有效果,也不会新开线程进行处理的。
  3. 只有在controller里面直接调用service里面的异步方法才会产生异步的效果。

综上所述,异步方法要正确的时候才会达到想要的结果,否则的话容易同步方法里面调用异步方法,导致异步方法没有效果,闹出笑话来。始终坚持学习,始终去实践测试代码,看一下执行的结果才能正确写出想要的代码,程序员一定要做到知其然知其所以然,共勉。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
打赏
0
0
0
0
503
分享
相关文章
Spring Boot 3 集成 Spring Security + JWT
本文详细介绍了如何使用Spring Boot 3和Spring Security集成JWT,实现前后端分离的安全认证概述了从入门到引入数据库,再到使用JWT的完整流程。列举了项目中用到的关键依赖,如MyBatis-Plus、Hutool等。简要提及了系统配置表、部门表、字典表等表结构。使用Hutool-jwt工具类进行JWT校验。配置忽略路径、禁用CSRF、添加JWT校验过滤器等。实现登录接口,返回token等信息。
90 12
|
11天前
|
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
59 17
JAVA线程池有哪些队列? 以及它们的适用场景案例
不同的线程池队列有着各自的特点和适用场景,在实际使用线程池时,需要根据具体的业务需求、系统资源状况以及对任务执行顺序、响应时间等方面的要求,合理选择相应的队列来构建线程池,以实现高效的任务处理。
85 12
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
47 8
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
159 5
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
37 1
如何使用Spring Boot进行表单登录身份验证:从基础到实践
如何使用Spring Boot进行表单登录身份验证:从基础到实践
73 5
如何用Spring Boot实现拦截器:从入门到实践
如何用Spring Boot实现拦截器:从入门到实践
58 5
使用Spring Boot编写测试用例:实践与最佳实践
使用Spring Boot编写测试用例:实践与最佳实践
127 0
Spring Boot 3.3中的优雅实践:全局数据绑定与预处理
【10月更文挑战第22天】 在Spring Boot应用中,`@ControllerAdvice`是一个强大的工具,它允许我们在单个位置处理多个控制器的跨切面关注点,如全局数据绑定和预处理。这种方式可以大大减少重复代码,提高开发效率。本文将探讨如何在Spring Boot 3.3中使用`@ControllerAdvice`来实现全局数据绑定与预处理。
79 2