• SpringBoot的异步调用介绍


    参考博客: 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就失效了!!!

  • 相关阅读:
    C#基础视频教程4.1 如何编写简单的计算器
    C#基础视频教程3.3 常见控件类型和使用方法
    C#基础视频教程3.2 常见控件类型和使用方法
    C#基础视频教程3.1 常见控件类型和使用方法
    C#基础视频教程2 常见数据类型和属性方法
    C#基础视频教程1 背景知识和安装配置
    为什么我的淘宝排名会突然下降?
    Idea项目如何迁移到Eclipse
    myeclipse部署项目的时候报No projects are available for deployment to this server但是项目明明存在
    idea如何将项目以eclipse保存
  • 原文地址:https://www.cnblogs.com/xumBlog/p/10890208.html
Copyright © 2020-2023  润新知