zoukankan      html  css  js  c++  java
  • @Scheduled阻塞导致未执行生效的情况分析及解决方案

    @Scheduled阻塞导致未执行生效的情况分析

    今天排查线上数据,发现数据并未更新,查看日志发现更新数据的定时任务并没有执行,而执行该定时任务的时间发现执行了另外的定时任务,所以因此初步判断可能是定时任务阻塞导致相同时间的定时任务有未执行任务。

    写了个DEMO果真复现了,@Scheduled注解的定时任务为单线程执行,所以必定会有阻塞情况。

    测试代码

    • 定时任务【1】DEMO代码
    @Component
    public class Test01 {
        // 每秒执行一次
        @Scheduled(cron = "0/1 * * * * ? ")
        public void test() {
            // 时分秒
            String nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
            // 日志打印
            System.out.println(nowTime + "   任务【1】执行  线程:" + Thread.currentThread().getName());
        }
    }
    
    • 定时任务【2】DEMO代码
    @Component
    public class Test02 {
        // 每5秒执行一次
        @Scheduled(cron = "0/5 * * * * ? ")
        public void test() {
            String nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
            System.out.println(nowTime + "   任务【2】执行  线程:" + Thread.currentThread().getName());
            try {
                // 模拟耗时任务,阻塞2s
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    

    服务启动后运行结果

    原因分析

    • 由程序运行后的打印结果可以发现两个任务均是使用的同一线程。
    • 任务【1】应该是每秒执行一次的,但是执行时间上可以发现,任务【1】的执行时间不是连续的,这就说明有时间点是任务【1】没有执行的,而这些时间点恰好任务【2】正在执行中,单线程的原因线程此时阻塞,从而导致这些时间点任务【1】没有执行。

    解决方案

    • 添加@Async注解或者使用自定义线程池执行任务

    代码这里就不贴了,就是在上面的任务【1】和任务【2】的@Scheduled注解上面添加一个注解@Async即可。

    多线程执行定时任务后的执行结果


    很明显,任务【1】每秒执行的时间连续了!!!没有未执行的情况。
    但需要注意的是,可以对@Async进行自定义配置,使其使用时,内部也是通过创建ThreadPoolExecutor线程池来执行。

    • 【推荐】一劳永逸,统一配置:实现SchedulingConfigurer接口
    @Configuration
    public class ScheduledConfig implements SchedulingConfigurer {
        @Override
        public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
            // 自定义调度器,设置为一个支持定时及周期性的任务执行的线程池,这里初始3个线程
            scheduledTaskRegistrar.setScheduler(Executors.newScheduledThreadPool(3));
        }
    }
    

    统一配置后便不需要添加@Async注解或者创建线程池来达到多线程了

    执行结果


    很明显,定时任务执行的线程达到多线程执行,任务【1】执行时间连续,没有出现未执行的情况,且线程也是反复使用的三个。

    查看setScheduler()方法源码:

    由源码也可以看出,自定义调度器的时候,只能设置TaskSchedulerScheduledExecutorService类型,除此之外的类型都会报错。

  • 相关阅读:
    POJ 1185 状压DP
    POJ 1321
    hdu 1384 查分约束
    hdu 2196 树形dp
    hdu 4612 双联通缩点+树形dp
    poj 3469 最小割模板sap+gap+弧优化
    hdu 4858 容器的简单模拟
    hdu 4857 逆向拓扑排序+反向输出
    isap算法模板poj 1273gap+弧优化 最大流
    ISAP 算法的学习
  • 原文地址:https://www.cnblogs.com/qukun/p/14889676.html
Copyright © 2011-2022 走看看