异步调用

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

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

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

  需要在启动类加入@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)
上一篇 2022年7月4日 下午6:36
下一篇 2022年7月4日 下午6:36


相关推荐

  • linux c——dup( )和dup2( )函数详解

    dup()函数和dup2()函数书上在文件操作那一章,已经讲过了,这周看重定向这块,发现它挺重要,就再看了回,记录下。1、dup函数头文件及函数定义:#include&amp;lt;unistd.h&amp;gt;intdup(intoldfd);dup用来复制参数oldfd所指的文件描述符。当复制成功是,返回最小的尚未被使用过的文件描述符,若有错误则返回-1.错误代码存入errno中…

    2022年4月4日
    158
  • idea iml 文件怎么更新_IDEA中的.iml文件和.idea文件夹

    idea iml 文件怎么更新_IDEA中的.iml文件和.idea文件夹IDEA 中的 iml 文件和 idea 文件夹初次使用 IDEA 创建一个 maven 工程 发现在目录结构中产生了两个不一样的东西 iml 文件和 idea 文件夹 非常好奇 所以立刻上网查找了这两个东西的信息 iml 是 intellijidea 的工程配置文件 里面是当前 project 的一些配置信息 Idea 存放项目的配置信息 包括历史记录 版本控制信息等 其实可以不用理它 如果觉得看着麻烦的话 我们

    2026年3月16日
    2
  • 关于头文件中的 static inline函数

    关于头文件中的 static inline函数关于头文件中的 staticinline 函数 nbsp nbsp 头文件中常见 staticinline 函数 于是思考有可能遇到的问题 如头文件经常会被包含会不会产生很多副本 网上说法不一 于是自己验证 经过 arm none eabi gcc 下测试后得出结论 nbsp nbsp inline 关键字实际上仅是建议内联并不强制内联 gcc 中 O0 优化时是不内联的 即使是 O2 以上 如果该函数被作为函数指针赋值

    2026年3月18日
    2
  • MATLAB矩阵合并「建议收藏」

    MATLAB矩阵合并「建议收藏」两个或多个矩阵的拼接(合并)操作:学习链接用[]做拼接时,有三种连接符:逗号(,),空格,分号(;)。逗号(,)和空格等价,表示不换行,直接横向拼接,横向拼接要求两个矩阵行数相同;分号(;)表示换行后纵向拼接,纵向拼接要求两个拼接的矩阵的列数相同。代码展示:1.横向拼接:1%逗号和空格表示横向拼接2A=zeros(4,2)3B=ones(4,1)4C=[AB]A=00000000B=11

    2022年6月25日
    120
  • python deepcopy「建议收藏」

    python deepcopy「建议收藏」1.copy.copy浅拷贝只拷贝父对象,不会拷贝对象的内部的子对象。2.copy.deepcopy深拷贝拷贝对象及其子对象一个很好的例子:import copya = [1, 2, 3, 4, [‘a’, ‘b’]]  #原始对象b = …

    2022年10月2日
    4
  • Python字典提取_python字典键对应的值

    Python字典提取_python字典键对应的值python字典操作提取key,valuedictionaryName[key]=value1.为字典增加一项2.访问字典中的值3、删除字典中的一项4、遍历字典5、字典遍历的key\value6、字典的标准操作符7、判断一个键是否在字典中8、python中其他的一些字典方法9、将两个字典合并a={‘a’:1,…

    2022年10月20日
    3

发表回复

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

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