异步调用

异步调用同步调用,即:程序按定义的顺序依次执行的过程,每一行代码执行过程必须等待上一行代码执行完毕后才执行。而异步调用指:程序在执行时,无需等待执行的返回值可继续执行后面的代码。回调。其主要是解决异步方法执行

大家好,又见面了,我是你们的朋友全栈君。

       同步调用,即:程序按定义的顺序依次执行的过程,每一行代码执行过程必须等待上一行代码执行完毕后才执行。而异步调用指:程序在执行时,无需等待执行的返回值可继续执行后面的代码。回调。其主要是解决异步方法执行结果的处理方法,比如在希望异步调用结束时返回执行结果,这个时候就可以考虑使用回调机制。

  需要在启动类加入@EnableAsync使异步调用@Async注解生效

@Component
public class SyncService {
    
    @Async
    public void asyncEvent() throws InterruptedException {
        //休眠1s
        Thread.sleep(1000);
        //log.info("异步方法输出:{}!", System.currentTimeMillis());
    }

}

  在默认情况下,未设置TaskExecutor时,默认是使用SimpleAsyncTaskExecutor这个线程池,但此线程不是真正意义上的线程池,因为线程不重用,每次调用都会创建一个新的线程。可通过控制台日志输出可以看出,每次输出线程名都是递增的。

  调用的异步方法,不能为同一个类的方法,因为Spring在启动扫描时会为其创建一个代理类,而同类调用时,还是调用本身的代理类的,所以和平常调用是一样的。其他的注解如@Cache等也是一样的道理,就是Spring的代理机制造成的。

  创建一个自定义的ThreadPoolTaskExecutor线程池:

@Configuration
public class Config {

    /**
     * 配置线程池
     * @return
     */
    @Bean(name = "asyncPoolTaskExecutor")
    public ThreadPoolTaskExecutor getAsyncThreadPoolTaskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(20);
        taskExecutor.setMaxPoolSize(200);
        taskExecutor.setQueueCapacity(25);
        taskExecutor.setKeepAliveSeconds(200);
        taskExecutor.setThreadNamePrefix("King-");
        // 线程池对拒绝任务(无线程可用)的处理策略,目前只支持AbortPolicy、CallerRunsPolicy;默认为后者
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //调度器shutdown被调用时等待当前被调度的任务完成
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        //等待时长
        taskExecutor.setAwaitTerminationSeconds(60);
        taskExecutor.initialize();
return taskExecutor; } }

  若需要在关闭线程池时等待当前调度任务完成后才开始关闭,可以通过简单的配置,进行优雅的停机策略配置。关键就是通过setWaitForTasksToCompleteOnShutdown(true)setAwaitTerminationSeconds方法。

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

      使用的是就只需要在@Async加入线程池名称即可:

@Async("asyncPoolTaskExecutor")
    public void asyncEvent() throws InterruptedException {
        //休眠1s
        Thread.sleep(1000);
        log.info("异步方法内部线程名称:{}!", Thread.currentThread().getName());
    }

  异步回调及超时处理

  需要异步回调的返回值时,就需要使用异步回调来完成了。主要就是通过Future进行异步回调。

@Async("asyncPoolTaskExecutor")
public Future<String> asyncEvent() throws InterruptedException {
    //休眠1s
    Thread.sleep(1000);
    log.info("异步方法内部线程名称:{}!", Thread.currentThread().getName());
    return new AsyncResult<>("异步方法返回值");
}

  AsyncResultSpring提供的一个Future接口的子类。然后通过isDone方法,判断是否已经执行完毕。

  超时处理

  对于Future配置超时,很简单,通过get方法即可,具体如下: 

//get方法会一直堵塞,直到等待执行完成才返回
//get(long timeout, TimeUnit unit) 在设置时间类未返回结果,会直接排除异常TimeoutException,messages为null
String result = doFutrue.get(60, TimeUnit.SECONDS);//60s

  超时后,会抛出异常TimeoutException类,此时可进行统一异常捕获即可

注意:

  @Async所修饰的函数不要定义为static类型,这样异步调用不会生效,

  @Async调用中的事务处理机制

  在@Async标注的方法,同时也适用了@Transactional进行了标注;在其调用数据库操作之时,将无法产生事务管理的控制,原因就在于其是基于异步处理的操作。那该如何给这些操作添加事务管理呢?可以将需要事务管理操作的方法放置到异步方法内部,在内部被调用的方法上添加@Transactional.
  例如: 方法A,使用了@Async/@Transactional来标注,但是无法产生事务控制的目的。方法B,使用了@Async来标注, B中调用了C、D,C/D分别使用@Transactional做了标注,则可实现事务控制的目的。
  基于@Async调用中的异常处理机制
  在异步方法中,如果出现异常,对于调用者caller而言,是无法感知的。

  

   

       

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/154204.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Kubernetes从懵圈到熟练:读懂这一篇,集群节点不下线

    Kubernetes从懵圈到熟练:读懂这一篇,集群节点不下线Kubernetes从懵圈到熟练:读懂这一篇,集群节点不下线

    2022年4月22日
    44
  • redis集群主从复制原理_主从关系紫音

    redis集群主从复制原理_主从关系紫音Redis主从复制主从复制简介主从复制的概念主从复制的作用主从复制工作流程阶段一:建立连接阶段主从连接(slave连接master)第一种方式第二种方式第三种方式授权访问阶段二:数据同步阶段工作流程数据同步阶段master说明数据同步阶段slave说明阶段三:命令传播阶段命令传播阶段的部分复制服务器的运行id复制缓冲区复制缓冲区内部工作原理复制缓冲区主从服务器复制偏移量(offset)数据同步+命令传播阶段工作流程心跳机制心跳阶段注意事项主从复制常见问题引发频繁的全量复制1引发频繁的全量复制2频繁的网络中

    2022年8月13日
    5
  • 最全的PHP后台管理系统源码「建议收藏」

    最全的PHP后台管理系统源码「建议收藏」一款PHP语言基于ThinkPhp6.x+Layui+MySQL等框架精心打造的一款模块化、插件化、高性能的前后端分离架构敏捷开发框架,可用于快速搭建前后端分离后台管理系统,本着简化开发、提升开发效率的初衷,框架自研了一套个性化的组件,实现了可插拔的组件式开发方式:单图上传、多图上传、下拉选择、开关按钮、单选按钮、多选按钮、图片裁剪等等一系列个性化、轻量级的组件,是一款真正意义上实现组件化开发的敏捷开发框架,框架已集成了完整的RBAC权限架构和常规基础模块,同时支持多

    2022年9月16日
    0
  • JS数组对象排序

    JS数组对象排序利用数组api——>sort来进行排序varperson=[{name:”Rom”,age:12},{name:”Bob”,age:22},{name:”Ma”,age:5},{name:”Tony”,age:25}]person.sort((a,b)=>{returna.age-b.age})//升序person.sort((a,b)=>{retu…

    2022年4月27日
    37
  • pycharm激活码2021.9【2021最新】

    (pycharm激活码2021.9)本文适用于JetBrains家族所有ide,包括IntelliJidea,phpstorm,webstorm,pycharm,datagrip等。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/ide…

    2022年3月27日
    51
  • 铸博皇御:贵金属技术分析基础入门知识「建议收藏」

    铸博皇御:贵金属技术分析基础入门知识「建议收藏」 在贵金属投资市场上,或许有很多投资者表示贵金属技术分析很难理解。特别是刚入门的新手,可能一开始对其并不容易理解,其实这可以理性地看待。贵金属技术分析是根据历史数据,以及开盘价、收盘价、最高价、最低价,利用数学统计的方法来进行综合统计计算。  一般进行分析时需要抛弃主观观念,客观地去分析价格的走向。虽然它不能够左右价格走向,但是可以由价格决定它的趋势走向。所以能不能学好贵金属技术分析,是多方面作用的结果。但需要提醒大家的是:用贵金属技术分析法,只能分析它的趋势,意味着不能完全依赖技术分析来行情作为决策重

    2022年5月28日
    34

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号