热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

SpringBoot异步调用方法实现场景代码实例

这篇文章主要介绍了SpringBoot异步调用方法实现场景代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

一、背景  

项目中肯定会遇到异步调用其他方法的场景,比如有个计算过程,需要计算很多个指标的值,但是每个指标计算的效率快慢不同,如果采用同步执行的方式,运行这一个过程的时间是计算所有指标的时间之和。比如:

  方法A:计算指标x,指标y,指标z的值,其中计算指标x需要1s,计算指标y需要2s,指标z需要3s。最终执行完方法A就是5s。

  现在用异步的方式优化一下

  方法A异步调用方法B,方法C,方法D,方法B,方法C,方法D分别计算指标x,指标y,指标z的值,那么最终执行完方法A的时间则是3s。

还有一种用途是当一个业务里面需要多个请求时,这时候异步并发请求所得到的回报远远是物有所值的。因为他是异步执行的,话不多说,一下是在springBoot里面使用并发请求;

二、spring boot中异步并发使用

2.1、appllication.yml

#****************集成Async线程池开始*******************
async: # Async线程池 配置
 executor:
  corepoolsize: 20
  maxpoolsize: 25
  queuecapacity: 40
  keepaliveseconds: 200
  threadnameprefix: appasync
  awaitterminationseconds: 60
#*****************集成Async线程池结束******************

2.2、配置线程池

@Configuration
@EnableAsync
public class ExecutorConfig {

  @Value("${async.executor.corepoolsize}")
  private Integer corePoolSize;

  @Value("${async.executor.maxpoolsize}")
  private Integer maxPoolSize;

  @Value("${async.executor.queuecapacity}")
  private Integer queueCapacity;

  @Value("${async.executor.keepaliveseconds}")
  private Integer keepAliveSeconds;

  @Value("${async.executor.threadnameprefix}")
  private String threadNamePrefix;

  @Value("${async.executor.awaitterminationseconds}")
  private Integer awaitTerminationSeconds;

  /**
   * 线程池
   *
   * @return
   */
  @Bean(name = "asyncExecutor")
  public Executor asyncExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    // 基础线程数 corePoolSize: 10
    executor.setCorePoolSize(corePoolSize);
    // 最大线程数 maxPoolSize: 15
    executor.setMaxPoolSize(maxPoolSize);
    // 队列长度 queueCapacity: 25
    executor.setQueueCapacity(queueCapacity);
    // 线程池维护线程所允许的空闲时间,单位为秒 keepAliveSeconds: 200
    executor.setKeepAliveSeconds(keepAliveSeconds);
    // 线程名字 threadNamePrefix: appasync
    executor.setThreadNamePrefix(threadNamePrefix);
    executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
    // 等待所有任务都完成再继续销毁其他的Bean
    executor.setWaitForTasksToCompleteOnShutdown(true);
    // 线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住
    executor.setAwaitTerminationSeconds(awaitTerminationSeconds);
    executor.initialize();
    return executor;
  }
}

2.3、线程池监控(这个可有可无,主要是为了对线程池参数及时的调优)

@RestController
@Slf4j
@RequestMapping("/pubapi/asyncExecutor")
public class AsyncExecutorController extends BaseController {

  @Resource(name = "asyncExecutor")
  private Executor asyncExecutor;

  @PostMapping("/monitor")public ResultBean> getAsyncExecutorData() {
    ResultBean> resultBean = ResultBeanUtil.error500();
    if (asyncExecutor == null) {
      return resultBean;
    }

    try {
      ThreadPoolTaskExecutor executorTask = (ThreadPoolTaskExecutor) asyncExecutor;
      ThreadPoolExecutor executor = executorTask.getThreadPoolExecutor();

      // 当前排队线程数
      int queueSize = executor.getQueue().size();
      // 当前活动线程数
      int activeCount = executor.getActiveCount();
      // 执行完线程数
      long completedThreadCount = executor.getCompletedTaskCount();
      // 总线程数
      long taskCount = executor.getTaskCount();
      // 初始线程数
      int poolSize = executor.getPoolSize();
      // 核心线程数
      int corePoolSize = executor.getCorePoolSize();
      // 线程池是否终止
      boolean isTerminated = executor.isTerminated();
      // 线城池是否关闭
      boolean isShutdown = executor.isShutdown();
      // 线程空闲时间
      long keepAliveTime = executor.getKeepAliveTime(TimeUnit.MILLISECONDS);
      // 最大允许线程数
      long maximumPoolSize = executor.getMaximumPoolSize();
      // 线程池中存在的最大线程数
      long largestPoolSize = executor.getLargestPoolSize();

      Map threadPoolData = new HashMap<>(18);
      threadPoolData.put("当前排队线程数", queueSize);
      threadPoolData.put("当前活动线程数", activeCount);
      threadPoolData.put("执行完线程数", completedThreadCount);
      threadPoolData.put("总线程数", taskCount);
      threadPoolData.put("初始线程数", poolSize);
      threadPoolData.put("核心线程数", corePoolSize);
      threadPoolData.put("线程池是否终止", isTerminated);
      threadPoolData.put("线城池是否关闭", isShutdown);
      threadPoolData.put("线程空闲时间", keepAliveTime);
      threadPoolData.put("最大允许线程数", maximumPoolSize);
      threadPoolData.put("线程池中存在的最大线程数", largestPoolSize);

      InetAddress inetAddress = IdWorker.getLocalHostLANAddress();
      Map resultData = new HashMap<>(4);
      resultData.put("ip", inetAddress.getHostAddress());
      resultData.put("threadPoolData", threadPoolData);

      resultBean = ResultBeanUtil.success("请求成功!", resultData);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return resultBean;
  }

}

2.4、代码中使用

public void getMap(){
    /**
     * 先将耗时的、相互之间无依赖的操作先执行,由于其执行结果暂时不是特别关注,所以
     */
    Future futureA = functionA();
    Future futureB = functionB();
    /**
     * 执行其他的操作,其实functionA(),functionB()也在工作
     */
    aaa();
    /**
     * 获取异步的结果,然后计算
     */
    try {
      String resultA =futureA.get();
      String resuleB = futureB.get();
    } catch (InterruptedException e) {
      e.printStackTrace();
    } catch (ExecutionException e) {
      e.printStackTrace();
    }
    
  }

  public Future functionA (){
    Future future = null;
    try {
      Thread.sleep(5000);
      future = new AsyncResult("functionA");
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    return future;
  }

  public Future functionB (){
    Future future = null;
    try {
      Thread.sleep(3000);
      future = new AsyncResult("functionB");
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    return future;
  }

  public void aaa(){
    System.out.println("我是");
  }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • Windows环境下详细教程:如何搭建Git服务
    Windows环境下详细教程:如何搭建Git服务 ... [详细]
  • Typora快捷键使用指南:提升写作效率的必备技巧 ... [详细]
  • 开发技巧分享:利用套索与矩形选择工具高效选取绘图中的全部字形节点
    开发技巧分享:利用套索与矩形选择工具高效选取绘图中的全部字形节点 ... [详细]
  • NanoPi2 使用体验深入解析(续篇)
    随着Raspberry Pi的问世,开源硬件领域迎来了前所未有的发展,激发了全球范围内的创新热潮。在中国,这一趋势同样催生了一系列类似的开发板,例如NanoPi 2。本文作为前篇的延续,将深入探讨NanoPi 2的实际使用体验,从性能、兼容性到应用场景,进行全面分析。 ... [详细]
  • 深入解析Java线程池原理及源码,助你轻松应对面试提问
    线程池作为一种高效的线程管理机制,在Java中扮演着重要角色。它通过预先创建并维护一定数量的线程,避免了频繁创建和销毁线程带来的性能开销,从而提高了应用程序的响应速度和系统稳定性。本文将深入探讨Java线程池的工作原理及其源码实现,帮助读者更好地理解和应用这一核心概念,为面试中的相关问题提供有力支持。 ... [详细]
  • 如何在CentOS 7.1中安全升级至glibc 2.18而不影响系统稳定性与现有功能 ... [详细]
  • gitlab+jenkins_gitlab+jenkins+docker
    gitlab+jenkins_gitlab+jenkins+docker ... [详细]
  • tarzxvffilename.tar.gz顺便我们了解下linux下压缩与解压命令大全.tar解包:tarxvffilename.tar打包:tarc ... [详细]
  • 软件开发史上最具影响力的十位编程大师(附图解)
    在软件开发领域,有十位编程大师对行业发展产生了深远影响。本文基于国外知名社区的一项评选,通过图文并茂的形式,详细介绍了这十位杰出人物,包括游戏开发先驱John Carmack等,为读者呈现了他们卓越的技术贡献与创新精神。 ... [详细]
  • 在CentOS虚拟环境中部署Java开发套件(JDK)的详细步骤,不仅适用于Linux系统,也适用于Windows系统的Java开发。本文将详细介绍如何在CentOS虚拟机中安装和配置JDK,包括环境准备、下载JDK安装包、解压安装、配置环境变量等关键步骤。通过本文的指导,开发者可以轻松完成JDK的部署,为后续的Java应用开发打下坚实的基础。 ... [详细]
  • 利用Mac上的Remote Desktop Manager实现与Ubuntu 16.04及Windows 10的远程桌面连接优化方案
    随着远程办公需求的增加,如何在不同操作系统之间高效地进行远程桌面连接成为了一个重要问题。本文介绍了一种利用Mac上的Remote Desktop Manager实现与Ubuntu 16.04及Windows 10远程桌面连接的优化方案。通过详细的操作步骤和配置方法,帮助用户在多平台环境中顺利进行远程工作,避免常见的技术障碍。 ... [详细]
  • 在安装 Greenplum 的过程中,正确配置 `gpinitsystem_config` 文件是至关重要的一步。本文详细介绍了如何优化该文件,以确保数据库集群的高效初始化和稳定运行。通过调整关键参数,用户可以更好地适应不同的硬件环境和业务需求,从而提升系统的整体性能。 ... [详细]
  • 在Linux系统中,通过使用`nohup`命令可以实现在后台运行进程,并将输出重定向到指定文件。具体命令示例如下:`nohup homessh root/anaconda3/bin/gunicorn -c gunicorn.conf flask_server:app > output.log 2>&1 &`。该命令不仅能够确保进程在用户退出终端后继续运行,还能将标准输出和错误输出重定向到`output.log`文件中,便于后续的数据处理和日志分析。 ... [详细]
  • 本文总结了 Apache Shiro 安全框架的学习体会,并通过具体应用实例进行了详细分析。Apache Shiro 是一个强大且灵活的安全框架,适用于各种应用程序的安全需求。通过对该框架的核心功能和使用方法的深入探讨,本文不仅帮助读者理解其基本概念和架构设计,还提供了实际项目中的应用示例,以便更好地掌握和运用这一工具。特别感谢开涛的博客文章,为本文提供了宝贵的参考和启发。 ... [详细]
  • 本文深入解析了Java编译过程,重点探讨了从源代码到字节码文件的转换机制。通过具体示例,如 `Hello.java` 的编译与反编译过程,详细介绍了 `javap -verbose` 命令的使用方法及其在字节码分析中的重要作用。此外,文章还讨论了字节码文件的结构特点及其在不同应用场景中的实际应用,为开发者提供了宝贵的参考。 ... [详细]
author-avatar
goxtop
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有