异步调用

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

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

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

  需要在启动类加入@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)


相关推荐

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

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

  • Ubuntu18.04 安装Jdk1.8[通俗易懂]

    Ubuntu18.04 安装Jdk1.8[通俗易懂]Ubuntu18.04安装Jdk1.8

  • docker启动mysql容器失败_docker容器

    docker启动mysql容器失败_docker容器什么是Docker?Docker是一种工具,它让容器创建,部署和运行应用程序变得更加容易。容器使开发人员可以将应用程序与所需的所有部分(如库和其他依赖项)打包在一起,并将其作为一个包进行部署。这样,借助容器,开发人员可以放心,该应用程序可以在任何其他Linux机器上运行,而不用管该机器的环境配置。安装DockerDesktop前往官方网站:www.docker.com/get-started根据操作系统,下载并安装对应的DockerDesktop。验…

  • socket传输中文出现乱码的解决[通俗易懂]

    socket传输中文出现乱码的解决[通俗易懂]socket传输中文出现乱码的解决 (2013-04-1114:57:03)转载▼ 分类: 技术知识socket服务端和客户端编码方式不一致将有可出现中文乱码问题,因此两边设成一样的就可以了socket服务端发送数据时设置编码方式PrintWriteroutput=newPrintWriter(new

  • 国内云计算厂商众生相:四大阵营十几家企业生存盘点

    国内云计算厂商众生相:四大阵营十几家企业生存盘点

  • CRC校验算法详解「建议收藏」

    CRC校验算法详解「建议收藏」CRC(CyclicRedundancyCheck)循环冗余校验是常用的数据校验方法,讲CRC算法的文章很多,之所以还要写这篇,是想换一个方法介绍CRC算法,希望能让大家更容易理解CRC算法。先

发表回复

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

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