分布式定时任务的异步处理

最近项目中遇到一个问题 , 在SpringBoot中设置了定时任务之后 , 在某个点总是没有执行 . 经过搜索研究发现 , spring 定时器任务scheduled-tasks默认配置是单线程串行执行的 . 即在当前时间点之内 . 如果同时有两个定时任务需要执行的时候 , 排在第二个的任务就必须等待第一个任务执行完毕执行才能正常运行.如果第一个任务耗时较久的话 , 就会造成第二个任务不能及时执行 . 这样就可能由于时效性造成其他问题 . 而在实际项目中 , 我们也往往需要这些定时任务是"各干各的" , 而不是排队执行.

以下为默认串行的定时任务代码

   

启动项目之后 , 发现控制台输出如下 :


可以发现 , 一直是pool-5-thread-1一个线程在执行定时任务 , 这显然不符合我们的业务需求.

如何把定时任务改造成异步呢 , 在spring中网上文档较多 , 不再叙述 . 但在SpringBoot找到的相关资料也是新建xml文件的方式配置 , 实际上这就违背了SpringBoot减少配置文件的初衷 .

在SpringBoot可以自定义以下线程池配置 :

    package com.xbz.config;
     
    @Configuration
    @EnableScheduling
    public class ScheduleConfig implements SchedulingConfigurer, AsyncConfigurer{
     
        /** 异步处理 */
        public void configureTasks(ScheduledTaskRegistrar taskRegistrar){
            TaskScheduler taskScheduler = taskScheduler();
            taskRegistrar.setTaskScheduler(taskScheduler);
        }
     
        /** 定时任务多线程处理 */
        @Bean(destroyMethod = "shutdown")
        public ThreadPoolTaskScheduler taskScheduler(){
            ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
            scheduler.setPoolSize(20);
            scheduler.setThreadNamePrefix("task-");
            scheduler.setAwaitTerminationSeconds(60);
            scheduler.setWaitForTasksToCompleteOnShutdown(true);
            return scheduler;
        }
     
        /** 异步处理 */
        public Executor getAsyncExecutor(){
            Executor executor = taskScheduler();
            return executor;
        }
     
        /** 异步处理 异常 */
        public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler(){
            return new SimpleAsyncUncaughtExceptionHandler();
        }
    }


此时再启动定时任务 , 就发现已经是异步处理的了 .

package com.xbz.config;
     
    import java.lang.reflect.Method;
    import java.util.concurrent.Executor;
    import java.util.concurrent.ThreadPoolExecutor;
     
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.TaskScheduler;
    import org.springframework.scheduling.annotation.AsyncConfigurer;
    import org.springframework.scheduling.annotation.EnableAsync;
    import org.springframework.scheduling.annotation.EnableScheduling;
    import org.springframework.scheduling.annotation.SchedulingConfigurer;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
    import org.springframework.scheduling.config.ScheduledTaskRegistrar;
     
    /**
     * @title 使用自定义的线程池执行异步任务 , 并设置定时任务的异步处理
     * @version 1.0
     */
    @Configuration
    @EnableAsync
    @EnableScheduling
    public class ExecutorConfig implements SchedulingConfigurer, AsyncConfigurer {
     
        private static final Logger LOG = LogManager.getLogger(ExecutorConfig.class.getName());
     
        @Autowired
        private TaskThreadPoolConfig config;
     
        @Override
        public Executor getAsyncExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setCorePoolSize(config.getCorePoolSize());
            executor.setMaxPoolSize(config.getMaxPoolSize());
            executor.setQueueCapacity(config.getQueueCapacity());
            executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
            executor.setThreadNamePrefix("taskExecutor-");
     
            // rejection-policy:当pool已经达到max size的时候,如何处理新任务
            // CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
            executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            executor.initialize();
            return executor;
        }
     
        /**
         * @title 异步任务中异常处理
         * @description
         * @author Xingbz
         * @createDate 2017年9月11日
         * @return
         * @see org.springframework.scheduling.annotation.AsyncConfigurer#getAsyncUncaughtExceptionHandler()
         * @version 1.0
         */
        @Override
        public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
            return new AsyncUncaughtExceptionHandler() {
                @Override
                public void handleUncaughtException(Throwable ex, Method method, Object... params) {
                    LOG.error("==========================" + ex.getMessage() + "=======================", ex);
                    LOG.error("exception method:" + method.getName());
                }
            };
        }
     
        @Override
        public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
            TaskScheduler taskScheduler = taskScheduler();
            taskRegistrar.setTaskScheduler(taskScheduler);
        }
        
        /**
         * 并行任务使用策略:多线程处理
         *
         * @return ThreadPoolTaskScheduler 线程池
         */
         @Bean(destroyMethod = "shutdown")
         public ThreadPoolTaskScheduler taskScheduler() {
             ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
             scheduler.setPoolSize(config.getCorePoolSize());
             scheduler.setThreadNamePrefix("task-");
             scheduler.setAwaitTerminationSeconds(60);
             scheduler.setWaitForTasksToCompleteOnShutdown(true);
             return scheduler;
         }
    }


如果项目中同时配置了异步任务的线程池和定时任务的异步线程处理 , 配置类如下 :    需要注意 , 这两个配置类只能同时配置一个 , 如果配置了第二个 , 则第一个就无需再用.

https://blog.csdn.net/xingbaozhen1210/article/details/78717692

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值