最近项目侧反馈定时任务会被几乎同时执行很多遍

和项目侧的同事了解到定时任务使用的是Scheduled注解的方式,定时任务设置的是fixedRateString的方式,并且添加了Async注解,期望是使用线程池的方式去执行任务。

本地搭建一个小程序

自定义一个线程池

@Bean(name = "asyncServiceExecutor")
    public Executor asyncServiceExecutor() {
        log.info("=====start asyncServiceExecutor=====");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        //配置核心线程数
        executor.setCorePoolSize(1);

        //配置最大线程数
        executor.setMaxPoolSize(1);

        //配置队列大小
        executor.setQueueCapacity(5);

        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("Task-Sce");

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    }

添加执行类

@Slf4j
@Component
public class ExceTask {
    AtomicInteger count = new AtomicInteger(1);

    @Scheduled(cron = "* * * * * ?")
    @Async("asyncServiceExecutor")
    public void test() {
        log.info("start:{}", DateUtil.now());
        try {
            Thread.sleep(100L * count.addAndGet(1));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        log.info("end:{}", DateUtil.now());
    }

}

运行结果如下
刚开始

14:06:30.003 INFO  [Task-Sce1] com.zna.ExceTask - start:2024-01-25 14:06:30
14:06:30.805 INFO  [Task-Sce1] com.zna.ExceTask - end:2024-01-25 14:06:30
14:06:31.003 INFO  [Task-Sce1] com.zna.ExceTask - start:2024-01-25 14:06:31
14:06:31.907 INFO  [Task-Sce1] com.zna.ExceTask - end:2024-01-25 14:06:31
14:06:32.005 INFO  [Task-Sce1] com.zna.ExceTask - start:2024-01-25 14:06:32
14:06:33.008 INFO  [Task-Sce1] com.zna.ExceTask - end:2024-01-25 14:06:33
14:06:33.009 INFO  [Task-Sce1] com.zna.ExceTask - start:2024-01-25 14:06:33
14:06:34.114 INFO  [Task-Sce1] com.zna.ExceTask - end:2024-01-25 14:06:34
14:06:34.115 INFO  [Task-Sce1] com.zna.ExceTask - start:2024-01-25 14:06:34
14:06:35.316 INFO  [Task-Sce1] com.zna.ExceTask - end:2024-01-25 14:06:35
14:06:35.316 INFO  [Task-Sce1] com.zna.ExceTask - start:2024-01-25 14:06:35
14:06:36.619 INFO  [Task-Sce1] com.zna.ExceTask - end:2024-01-25 14:06:36
14:06:36.620 INFO  [Task-Sce1] com.zna.ExceTask - start:2024-01-25 14:06:36
14:06:38.024 INFO  [Task-Sce1] com.zna.ExceTask - end:2024-01-25 14:06:38
14:06:38.024 INFO  [Task-Sce1] com.zna.ExceTask - start:2024-01-25 14:06:38
14:06:39.529 INFO  [Task-Sce1] com.zna.ExceTask - end:2024-01-25 14:06:39
14:06:39.530 INFO  [Task-Sce1] com.zna.ExceTask - start:2024-01-25 14:06:39

然后过了一会之后,事情变的诡异起来,因为我设置的是随着执行次数变多,线程睡眠的时间越长,当线程睡眠的时间超过间隔时间时

14:06:41.134 INFO  [Task-Sce1] com.zna.ExceTask - end:2024-01-25 14:06:41
14:06:41.135 INFO  [Task-Sce1] com.zna.ExceTask - start:2024-01-25 14:06:41
14:06:42.839 INFO  [Task-Sce1] com.zna.ExceTask - end:2024-01-25 14:06:42
14:06:42.840 INFO  [Task-Sce1] com.zna.ExceTask - start:2024-01-25 14:06:42
14:06:44.642 INFO  [Task-Sce1] com.zna.ExceTask - end:2024-01-25 14:06:44
14:06:44.642 INFO  [Task-Sce1] com.zna.ExceTask - start:2024-01-25 14:06:44
14:06:46.544 INFO  [Task-Sce1] com.zna.ExceTask - end:2024-01-25 14:06:46
14:06:46.544 INFO  [Task-Sce1] com.zna.ExceTask - start:2024-01-25 14:06:46
14:06:48.006 INFO  [scheduling-2] com.zna.ExceTask - start:2024-01-25 14:06:48
14:06:48.548 INFO  [Task-Sce1] com.zna.ExceTask - end:2024-01-25 14:06:48
14:06:48.549 INFO  [Task-Sce1] com.zna.ExceTask - start:2024-01-25 14:06:48
14:06:50.108 INFO  [scheduling-2] com.zna.ExceTask - end:2024-01-25 14:06:50

可见突然出现了scheduling-2的线程,按照线程池的命名规则不应该出现这样的问题。
这样就会发现定时任务执行的间隔时间不会按照设定的去走了。

如何解决

建议定时任务执行的时间要低于间隔的时间
将Async注解去掉
当程序中一共有n个定时任务时,可以添加spring.task.scheduling.pool.size=n配置,这样Scheduled的核心线程数就会有n个,避免出现任务之间互相阻塞的情况。
如果使用Async注解,务必要保证定时任务的执行时间小于间隔时间。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐