spring定时任务不生效问题

问题产生的业务背景:

1、三个定时任务,触发时间点都是每周一0点
2、其中一个任务需要基于其他两个任务处理的数据
代码实现:
通过CountDownLatch来实现业务逻辑需要,其中两个先行任务通过手动new的形式来传入依赖的接口和CountDownLatch,另外一个任务就交给sping管理。代码如下:

@Component
@Slf4j
public class DutyWorkTrigger {

    @Resource
    private IDutyWorkTaskService dutyWorkTaskService;

    @Resource
    private IDutyWorkExecuteService dutyWorkExecuteService;

    @Resource
    private DutyEffectEvaluateWorker dutyEffectEvaluateWorker;

    @Resource
    private HBTThreadPool hbtThreadPool;

    private CountDownLatch countDownLatch = new CountDownLatch(2);

//    @Scheduled(cron = "0 0 0 ? * MON")
    @Scheduled(cron = "0 11 15 * * ?")
    public void task() {
        hbtThreadPool.getExecutor.execute(new DutyWorkTaskWorker(dutyWorkTaskService, countDownLatch));
    }

//    @Scheduled(cron = "0 0 0 ? * MON")
    @Scheduled(cron = "0 11 15 * * ?")
    public void taskExecute() {
        hbtThreadPool.getExecutor.execute(new DutyWorkExecuteWorker(dutyWorkExecuteService, countDownLatch));
    }

//    @Scheduled(cron = "0 0 0 ? * MON")
    @Scheduled(cron = "0 11 15 * * ?")
    public void evaluate() {
        try {
            countDownLatch.await();
            log.info("运行效果评估任务开始。。。");
            hbtThreadPool.getExecutor.execute(dutyEffectEvaluateWorker);
        } catch (InterruptedException e) {
            log.error("countDownLatch Interrupted", e);
            throw new RuntimeException(e);
        } finally {
            // 定时任务,不会出现并发触发导致的更新countDownLatch错位
            countDownLatch = new CountDownLatch(2);
        }
    }

那么问题来了:

启动后,发现任务不执行,没有打任何日志(先行的两个worker中有打日志)

分析:

经过调试后发现,到点触发时,先执行了第三个任务,countDownLatch.await()停止了,先行的两个任务不执行了,也就不会调用countDownLatch.countDown()进行计数减一,结果导致第三个任务就一直等待中。那么为什么两个先行的任务不行了?那么遵循,遇到问题先网上搜一波的原则,我找到了答案。

原因:

spring定时任务框架默认是单线程,只有前面一个任务执行完后,才会继续进行下一个任务,那么这边三个任务是相同的触发时间,而恰好第三个任务排在第一个执行,但因为被countDownLatch.await()住,在等待其他两个任务执行进行计数减一,而那两个任务却因为定时任务框架的机制在等待第三个任务执行结束,死循环。。。

解决:

问题的根本原因是,定时任务框架是单线程的,不能并行执行相同时间点的任务。要解决,只要把单线程的改成多线程的,而spring也是支持的,代码如下,加个配置,创建自定义的定时任务线程池,而不是用默认的。

@Configuration
public class ScheduledTaskConfig {
    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler(){
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(3);                        // 线程池大小
        threadPoolTaskScheduler.setThreadNamePrefix("taskExecutor-");   // 线程名称
        threadPoolTaskScheduler.setAwaitTerminationSeconds(60);         // 等待时长
        threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true);  // 调度器shutdown被调用时等待当前被调度的任务完成
        return threadPoolTaskScheduler;
    }
}

注意:我这边是在启动类上加的@EnableScheduling注解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr Yin

您获益,我得意,您打赏,我敬礼

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值