zoukankan      html  css  js  c++  java
  • springboot异步线程(二)

    前言

    上一篇中讲了关于TaskExecutor的一些相关知识,本篇就是实战篇,看看异步线程使如何使用的

    正文

    本篇文章使用springboot 2.2.1.RELEASE

    一.前奏,直接使用,无任何配置

    1. 启动异步注解

    在springboot启动类上添加注解@EnableAsync

    
    @SpringBootApplication
    @EnableAsync
    public class AsyncApplication {
        public static void main(String[] args) {
            SpringApplication.run(AsyncApplication.class, args);
        }
    }
    
    
    1. 使用@Async注解

    在需要的方法上使用@Async注解:

    
    public interface AsyncService {
        @Async
        void testAsync();
        @Async
        void testOne();
    }
    
    @Service
    public class AsyncServiceImpl implements AsyncService {
        private static final Logger log= LoggerFactory.getLogger(AsyncServiceImpl.class);
        @Override
        public void testAsync(){
            log.info("========testAsync运行=========="+Thread.currentThread().getName());
        }
        @Override
        public void testOne(){
            log.info("ThreadName:===one===="+Thread.currentThread().getName());
        }
    }
    
    1. controller 调用
      在controller层调用异步方法,注意,异步方法最好通过注入的方式调用,如果是同类方法或工具类方法,@Async可能不会取作用。
    
    @RestController
    @RequestMapping("/test")
    public class TestController {
        private final AsyncService asyncService;
        @Autowired
        public TestController(AsyncService asyncService) {
            this.asyncService = asyncService;
        }
    
        @GetMapping
        public String test(){
            asyncService.testAsync();
            asyncService.testOne();
            return "SUCCESS";
        }
    }
    
    
    1. 结果
    
    2019-12-27 15:06:30.159  INFO 14756 --- [         task-1] c.e.async.service.impl.AsyncServiceImpl  : ========testAsync运行==========task-1
    2019-12-27 15:06:30.160  INFO 14756 --- [         task-2] c.e.async.service.impl.AsyncServiceImpl  : ThreadName:===one====task-2
    
    
    1. 问题

    很多人到这里就差不多完事了,我第一次用springboot的异步也是这样。其实这里还有问题:

    • 为什么线程名字是task-,而不是很多博客所说的SimpleAsyncTaskExecutor-
    • 为什么应用在启动时创建了一个名为:applicationTaskExecutorExecutor Service
    1. 原因

    这是因为springboot版本的原因:

    • springboot2.1版本新加入了明为TaskExecutionAutoConfiguration的一个配置类,在没有实现Executor的情况是会自动注入一个nameapplicationTaskExecutorThreadPoolTaskExecutor,具体属性可以点进去看一看,这里就不细说了,关键源码如下:
        @Lazy
    	@Bean(name = { APPLICATION_TASK_EXECUTOR_BEAN_NAME,
    			AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME })
    	@ConditionalOnMissingBean(Executor.class)
    	public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {
    		return builder.build();
    	}
    
    
    • springboot2.1版本之前,没有这个TaskExecutionAutoConfiguration类,所以才会是网上很多博客所说的SimpleAsyncTaskExecutor,具体的源码在下一篇文章中讲

    二. ThreadPoolTaskExecutor

    如何使用ThreadPoolTaskExecutor。

    
    @Configuration
    public class AsyncConfig {
        @Bean(name = "threadPoolTaskExecutor")
        public ThreadPoolTaskExecutor testTaskExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            //线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
            executor.setThreadNamePrefix("courses-schedule-");
            //最大线程数10:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
            executor.setMaxPoolSize(10);
            //核心线程数3:线程池创建时候初始化的线程数
            executor.setCorePoolSize(3);
            //缓冲队列0:用来缓冲执行任务的队列
            executor.setQueueCapacity(5);
            //允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
            executor.setKeepAliveSeconds(60);
            // 当线程池已满,且等待队列也满了的时候,直接抛弃当前线程(不会抛出异常)
    //        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
    //        executor.initialize();
            return executor;
        }
    }
    
    

    注意在使用@Async注解时在注解里面带上参数:@Async("threadPoolTaskExecutor")

    三. ConcurrentTaskExecutor

    如何使用ConcurrentTaskExecutor。

    
        @Bean(name = "concurrentTaskExecutor")
        public TaskExecutor concurrentTaskExecutor () {
            return new ConcurrentTaskExecutor(
                    Executors.newFixedThreadPool(3));
        }
        
    

    注意在使用@Async注解时在注解里面带上参数:@Async("concurrentTaskExecutor")

    四 接口实现

    AsyncConfig:这里需要实现AsyncConfigurer接口并重写里面得接口

    
    @Configuration
    public class AsyncConfig implements AsyncConfigurer {
        @Override
        public Executor getAsyncExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            //线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
            executor.setThreadNamePrefix("courses-schedule-");
            //最大线程数10:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
            executor.setMaxPoolSize(10);
            //核心线程数3:线程池创建时候初始化的线程数
            executor.setCorePoolSize(3);
            //缓冲队列0:用来缓冲执行任务的队列
            executor.setQueueCapacity(5);
            //允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
            executor.setKeepAliveSeconds(60);
            // 当线程池已满,且等待队列也满了的时候,直接抛弃当前线程(不会抛出异常)
    //        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
    //        executor.initialize();
            return executor;
        }
        @Override
        public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
            return new AsyncExceptionHandler();
        }
    }
    
    

    AsyncExceptionHandler:

    
    public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
        @Override
        public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
            System.out.println("Exception Cause - " + throwable.getMessage());
            System.out.println("Method name - " + method.getName());
            for (Object param : obj) {
                System.out.println("Parameter value - " + param);
            }
        }
    }
    
    

    这个直接使用,不用做其他操作

    五 说明

    1. 上面列出的方式,可以根据自己的需求做出选择,最好选择一种
    2. 如果存在两种及以上,请在使用@Async时加上需要使用哪一个处理,如果没有指明使用哪一种处理,最后会默认使用SimpleAsyncTaskExecutor来处理异步任务。

    最后

    本篇文章主要是使用方法,如何去使用springboot的异步线程。

    项目源码

    参考:

    1. Spring Boot Async Task Executor
    2. Spring 官方文档
    3. 新手也能看懂的 SpringBoot 异步编程指南
    4. TaskExecutionAutoConfiguration
  • 相关阅读:
    VMware安装最新版CentOS7图文教程
    git 本地给远程仓库创建分支 三步法
    git如何利用分支进行多人开发
    题解 洛谷P6478 [NOI Online #2 提高组] 游戏
    题解 CF1146D Frog Jumping
    题解 洛谷P6477 [NOI Online #2 提高组] 子序列问题
    题解 LOJ2472 「九省联考 2018」IIIDX
    题解 CF1340 A,B,C Codeforces Round #637 (Div. 1)
    题解 LOJ3284 「USACO 2020 US Open Platinum」Exercise
    windows上的路由表
  • 原文地址:https://www.cnblogs.com/guoyuchuan/p/12051450.html
Copyright © 2011-2022 走看看