You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Helidon 3.2.1中@Scheduled的concurrentExecution属性行为疑问

问题原因与解决办法

问题根源

你设置的concurrentExecution = false未生效,核心原因是:Helidon的@Scheduled注解的并发控制仅针对被注解的方法本身(即stuckThreadShooter方法),而你的方法只是把耗时的run()逻辑提交到了自定义线程池,方法本身瞬间就执行完毕——调度器会判定当前任务已结束,自然会按20秒间隔准时触发下一次任务,完全不会理会线程池内的任务是否还在运行。

解决方案

方案1:移除自定义线程池,直接在注解方法内执行耗时逻辑

将耗时操作直接放在stuckThreadShooter方法中,此时concurrentExecution = false会生效,调度器会等待当前任务执行完成后,再计算下一次触发时间。

修改后的代码:

@Scheduled(value= "0/20 * * * * ?", concurrentExecution = false)
public void stuckThreadShooter() {
    System.out.println("Starting fixed rate execution at" + new Date().toString());
    System.out.println("Starting run for thread: " + Thread.currentThread().getName()+ " "+ new Date().toString());
    run();
}

private static void run(){
 try {
    Thread.sleep(25000);
    System.out.println("Completed run for thread: " + Thread.currentThread().getName()+ " "+ new Date().toString());
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
}

对应的输出会变为:

Starting fixed rate execution atTue Jun 13 15:54:20 IST 2023
Starting run for thread: helidon-scheduler-1 Tue Jun 13 15:54:20 IST 2023
Completed run for thread: helidon-scheduler-1 Tue Jun 13 15:54:45 IST 2023
Starting fixed rate execution atTue Jun 13 15:54:45 IST 2023
Starting run for thread: helidon-scheduler-1 Tue Jun 13 15:54:45 IST 2023
Completed run for thread: helidon-scheduler-1 Tue Jun 13 15:55:10 IST 2023

可以看到,下一次任务会等上一次完全执行完毕后才触发。

方案2:保留自定义线程池,自行控制任务并发

如果必须使用自定义线程池,需自行添加并发控制逻辑,比如用原子标记确保上一个线程池任务完成后,才允许执行下一次任务提交。

示例代码:

private ExecutorService executorService = Executors.newFixedThreadPool(1);
private final AtomicBoolean isTaskRunning = new AtomicBoolean(false);

@Scheduled(value= "0/20 * * * * ?", concurrentExecution = false)
public void stuckThreadShooter() {
    // 检查是否有任务在运行,有则直接跳过本次触发
    if (!isTaskRunning.compareAndSet(false, true)) {
        System.out.println("Previous task still running, skip this trigger at " + new Date().toString());
        return;
    }
    
    System.out.println("Starting fixed rate execution at" + new Date().toString());
    executorService.execute(()->{
        try {
            System.out.println("Starting run for thread: " + Thread.currentThread().getName()+ " "+ new Date().toString());
            run();
        } finally {
            // 任务完成后重置标记
            isTaskRunning.set(false);
        }
    });
}

private static void run(){
 try {
    Thread.sleep(25000);
    System.out.println("Completed run for thread: " + Thread.currentThread().getName()+ " "+ new Date().toString());
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
}

这种情况下,当调度器触发下一次任务时,会检查线程池内的任务状态,若未完成则跳过本次触发,直到上一个任务结束后才会处理下一次调度。


内容的提问来源于stack exchange,提问作者Asif Iqbal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 19:53:08