参考博客: https://www.cnblogs.com/jebysun/p/9675345.html

https://blog.csdn.net/weixin_38399962/article/details/82146480

何为异步调用

说异步调用前,我们说说它对应的同步调用。通常开发过程中,一般上我们都是同步调用,即:程序按定义的顺序依次执行的过程,每一行代码执行过程必须等待上一行代码执行完毕后才执行。而异步调用指:程序在执行时,无需等待执行的返回值可继续执行后面的代码。显而易见,同步有依赖相关性,而异步没有,所以异步可并发执行,可提高执行效率,在相同的时间做更多的事情。

题外话:处理异步、同步外,还有一个叫回调。其主要是解决异步方法执行结果的处理方法,比如在希望异步调用结束时返回执行结果,这个时候就可以考虑使用回调机制。

先自定义一个线程池, 这里采用java的代码来配置, 如下面的ThreadPoolConfig.java内容:

import java.util.concurrent.ThreadPoolExecutor;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
public class ThreadPoolConfig {
@Bean(name = "asyncPoolTaskExecutor") // 这里bean的name值在下面要用到
public ThreadPoolTaskExecutor getAsyncThreadPoolTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(20);
taskExecutor.setMaxPoolSize(200);
taskExecutor.setQueueCapacity(25);
taskExecutor.setKeepAliveSeconds(200);
taskExecutor.setThreadNamePrefix("cmnd-");
//线程池对拒绝任务(无线程可用)的处理策略,目前只支持AbortPolicy/CallerRunsPolicy;默认为后者
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//调度器shutdown被调用时等待当前被调度的任务完成
taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
//等待时长
taskExecutor.setAwaitTerminationSeconds(60);
taskExecutor.initialize();
return taskExecutor;
} }

这里简单说明下,关于ThreadPoolTaskExecutor参数说明:

corePoolSize:线程池维护线程的最少数量
keepAliveSeconds:允许的空闲时间,当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
maxPoolSize:线程池维护线程的最大数量,只有在缓冲队列满了之后才会申请超过核心线程数的线程
queueCapacity:缓存队列
rejectedExecutionHandler:线程池对拒绝任务(无线程可用)的处理策略。这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务。还有一个是AbortPolicy策略:处理程序遭到拒绝将抛出运行时RejectedExecutionException。
而在一些场景下,若需要在关闭线程池时等待当前调度任务完成后才开始关闭,可以通过简单的配置,进行优雅的停机策略配置。关键就是通过setWaitForTasksToCompleteOnShutdown(true)和setAwaitTerminationSeconds方法。

setWaitForTasksToCompleteOnShutdown:表明等待所有线程执行完,默认为false。
setAwaitTerminationSeconds:等待的时间,因为不能无限的等待下去

再给出AsyncService.java内容

import java.util.concurrent.Future;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service; @Service(value = "asyncService")
public class AsyncService { private static final Logger LOG = LogManager.getLogger(AsyncService.class);
   
    // 我这里写的异步任务是必须有返回值的, 使用AsyncResult来返回
@Async(value= "asyncPoolTaskExecutor") // 这里的value必须写成上面自定义的线程池name, 要不然会用默认的线程池来执行下面的代码
public Future<String> testAsync(int i) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
LOG.error(e.getMessage(), e);
Thread.currentThread().interrupt();
}
return new AsyncResult<>(String.format("testAsyncTask->{%s}", i));
} }

最后给出AsyncTaskController.java内容:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping; import com.xum.cmnd.service.AsyncService; @EnableAsync
@Controller(value = "asyncTaskController")
@RequestMapping(value = "/async")
public class AsyncTaskController { private static final Logger LOG = LogManager.getLogger(AsyncTaskController.class); @Autowired
private AsyncService asyncService; @PostMapping(value = "/test")
public void testAsync() throws InterruptedException, ExecutionException {
List<Future<String>> futures = new ArrayList<>();
for(int i = 1; i <= 10; i++) {
Future<String> future = asyncService.testAsync(i);
futures.add(future);
}
for (Future<String> future : futures) {
String result = future.get();
LOG.info("result:" + result);
}
} }

启动项目, 然后用postman或则在浏览器中输入http://localhost:8080/async/test这条api, 看eclipse的console中打印的log, 如下

...controller.AsyncTaskController][37]:result:testAsyncTask->{1}
...controller.AsyncTaskController][37]:result:testAsyncTask->{2}
...controller.AsyncTaskController][37]:result:testAsyncTask->{3}
...controller.AsyncTaskController][37]:result:testAsyncTask->{4}
...controller.AsyncTaskController][37]:result:testAsyncTask->{5}
...controller.AsyncTaskController][37]:result:testAsyncTask->{6}
...controller.AsyncTaskController][37]:result:testAsyncTask->{7}
...controller.AsyncTaskController][37]:result:testAsyncTask->{8}
...controller.AsyncTaskController][37]:result:testAsyncTask->{9}
...controller.AsyncTaskController][37]:result:testAsyncTask->{10}

注意:

1. 一定要批量读取结果, 否则不能达到异步的效果!!!

2、异步方法和调用类不要在同一个类中!!!

3、注解扫描时,要注意过滤,避免重复实例化,因为存在覆盖问题,@Async就失效了!!!

SpringBoot的异步调用介绍的更多相关文章

  1. springboot之异步调用@Async

    原文:http://www.cnblogs.com/xuwenjin/p/8858050.html 引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交 ...

  2. springboot实现异步调用

    介绍 所谓的异步执行其实就是使用多线程的方式实现异步调用. 异步有什么好处呢? 如果一个业务逻辑执行完成需要多个步骤,也就是调用多个方法去执行, 这个时候异步执行比同步执行相应更快.不过要注意异步请求 ...

  3. springboot:异步调用@Async

    在后端开发中经常遇到一些耗时或者第三方系统调用的情况,我们知道Java程序一般的执行流程是顺序执行(不考虑多线程并发的情况),但是顺序执行的效率肯定是无法达到我们的预期的,这时就期望可以并行执行,常规 ...

  4. springboot的异步调用

    package com.handsight.platform.fras.aapp; import java.util.Locale; import org.slf4j.Logger; import o ...

  5. SpringBoot中异步请求和异步调用(看这一篇就够了)

    原创不易,如需转载,请注明出处https://www.cnblogs.com/baixianlong/p/10661591.html,否则将追究法律责任!!! 一.SpringBoot中异步请求的使用 ...

  6. spring boot实现异步调用

    今天在这里学习下使用springboot的异步调用async 首先使用@EnableAsync开启异步功能 /** * @author fengzp * @date 17/5/8 * @email f ...

  7. springboot 异步调用Async使用方法

    引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring 3. ...

  8. SpringBoot | 第二十一章:异步开发之异步调用

    前言 上一章节,我们知道了如何进行异步请求的处理.除了异步请求,一般上我们用的比较多的应该是异步调用.通常在开发过程中,会遇到一个方法是和实际业务无关的,没有紧密性的.比如记录日志信息等业务.这个时候 ...

  9. springBoot中实现自定义属性配置、实现异步调用、多环境配置

    springBoot中其他相关: 1:springBoot中自定义参数: 1-1.自定义属性配置: 在application.properties中除了可以修改默认配置,我们还可以在这配置自定义的属性 ...

随机推荐

  1. jeecms 评论相关

    html WEB-INF-t-cms-www-gyxrmyy-content news.html 内容详情页 inc_comment_input.html 评论输入框 inc_comment_list ...

  2. Dijkstra 路径规划 C#

    示例无向图如下:(起始点为v0) 邻接矩阵为: 注意:其中没有连接的边和自己到自己的点权值用10000表示. 代码: static void Main(string[] args) { , , , , ...

  3. 【前端自动化】Gulp的使用(一):安装gulp

    作为一个.NET码农,在前端高速发展的时代,深深感觉自己那么点“前端”技术不够看,比如开发出来的js css等文件庞大,不便于管理,还记得以前的开发就是累加 html  css   jquery, 现 ...

  4. c++常考算法知识点汇总

    前言:写这篇博客完全是给自己当做笔记用的,考虑到自己的c++基础不是很踏实,只在大一学了一学期,c++的面向对象等更深的知识也一直没去学.就是想当遇到一些比较小的知识,切不值得用一整篇 博客去记述的时 ...

  5. IIS中使用子目录文件作为默认文档(Default Document)替代重定向

    以前一直以为IIS应用程序的默认文档只能设置根目录下的文件,像index.html,default.aspx等,后来经同事指点,原来子目录或者子应用程序下的文件也可以添加到根应用程序的默认文档列表中. ...

  6. JavaWeb:Servlet技术

    JavaWeb:Servlet技术 快速开始 Servlet是什么 Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 ...

  7. Activity有四种加载模式:standard(默认), singleTop, singleTask和 singleInstance

    standard:Activity的默认加载方法,即使某个Activity在Task栈中已经存在,另一个activity通过Intent跳转到该activity,同样会新创建一个实例压入栈中.例如:现 ...

  8. SpringBoot整合MyBatis之xml配置

    现在业界比较流行的数据操作层框架 MyBatis,下面就讲解下 Springboot 如何整合 MyBatis,这里使用的是xml配置SQL而不是用注解.主要是 SQL 和业务代码应该隔离,方便和 D ...

  9. Unity---UNet学习(2)----简单mmo游戏实现

    1.实现步骤 新建空物体Controller,添加Network Manager.HUD组件. 创建Player模型,添加Inentity组件. Player添加脚本控制移动,只有当为本地用户才执行. ...

  10. angularJs中对时间戳的处理

    一. ng表达式 <!-- 表达式中使用 --> {{ dt1 | date:'yyyy-MM-dd HH:mm:ss' }} 二. 控制器中使用 //controller必须注入 $fi ...