异步调用

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

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

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

  需要在启动类加入@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而言,是无法感知的。

  

   

       

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • SOP是什么?SOP的作用是什么?如何编写SOP?

    SOP是什么?SOP的作用是什么?如何编写SOP?SOP是由StandardOperationProcedure这三个英文单词的首个字母组合而成。也就是以统一化的标准将操作流程的步骤和要求罗列出来,用于指导和规范日常工作。SOP的核心,就是把特定流程的关键问题细化及量化。SOP是以文件的方式归纳总结操作人员在实际生产过程中的具体操作步骤和应当要注意的事项,它是车间现场操作人员的作业指导模板,也是质量检验人员用于检测指导工作的依据。SOP的作用:1、把企业长期累积的经验技术记录归纳,汇总成简单易懂的标准化文件,即使出现操作人员变动也不会使已有的技

  • 做一个“代码模块”交易的网站

    做一个“代码模块”交易的网站

  • ThinkPHP函数详解:L方法

    ThinkPHP函数详解:L方法

  • ansi utf-8编码_utf8是等长编码吗

    ansi utf-8编码_utf8是等长编码吗原文地址:http://www.yanwushu.com/post/4.html1.ANSI指AmericanNationalStandardsInstitute(美国国家标准学会)。2.ANSI编码不是一种具体的编码方式,而是一种指定在某些环境下使用某些编码方式的标准。比如,在中文环境中ANSI的编码标准为GBK,在日语环境中ANSI的编码标准则是Shi

  • Ubuntu18.04.3虚拟机安装步骤(图文教程,非常详细!!!)

    Ubuntu18.04.3虚拟机安装步骤(图文教程,非常详细!!!)原创:丶无殇2019-9-6虚拟机的安装步骤就不教学了!自行百度!接下来教学ubuntu18.04.3desktop_amd64版本的安装和配置教程软件下载地址详细介绍:http://bencky.ml/linux下载速度很快:25MB/s左右一、ubuntu安装教…

  • C语言回文字符串

    C语言回文字符串“回文串”是一个正读和反读都一样的字符串,字符串由数字和小写字母组成,比如“level”或者“abcdcba”等等就是回文串。请写一个程序判断读入的字符串是否是“回文”。输入:包含多个测试实例,每一行对应一个字符串,串长最多100字母。输出:对每个字符串,输出它是第几个,如第一个输出为”case1:”;如果一个字符串是回文串,则输出”yes”,否则输出”no”,在yes/no之前用一个空格…

发表回复

您的电子邮箱地址不会被公开。

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