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

调用shutdown后ScheduledExecutorService仍运行如何取消定时任务

问题根因

ScheduledExecutorService调用shutdown()后仍执行周期任务是符合API设计语义的,不是异常:

  • shutdown()的作用仅为阻止新任务提交,已进入等待队列的周期任务默认会继续执行已调度的轮次,不会被自动清除
  • 你提供的示例代码本身存在两处逻辑错误,进一步导致日志时序和执行行为不符合预期:
    • funcA("shutdown-")被写在了shutdown()方法的外部,类实例化时就会执行该日志打印,根本不是shutdown流程触发的输出,日志时序完全不可靠
    • 线程池终止等待逻辑存在语法问题,第二个awaitTermination未传入合法的超时时间参数,且任务内部未做中断响应,就算调用shutdownNow()也无法快速终止正在运行的任务
彻底取消周期任务的正确实现

不要依赖线程池shutdown方法自动清理周期任务,按以下步骤实现可以完全终止调度:

  • 保存周期调度方法返回的ScheduledFuture实例,这是绑定对应周期任务的唯一精准控制句柄
  • 执行shutdown流程时,首先调用ScheduledFuture.cancel()主动取消周期任务,禁止后续轮次调度:如果需要中断正在执行的任务传true,允许当前正在跑的任务执行完再停传false
  • 任务内部增加中断响应逻辑,不要吞InterruptedException,收到中断信号后快速退出执行
  • 补全线程池终止等待逻辑,设置合理的超时时间,最终保留线程中断状态
修正后的可运行代码
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class Test {
    private static final Logger LOGGER = LoggerFactory.getLogger(Test.class);
    // 配置合理的终止等待超时
    private static final long INITIAL_TERMINATION_WAIT_SEC = 5;
    private static final long RETRY_TERMINATION_WAIT_SEC = 5;

    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    // 保存周期任务的调度句柄
    private ScheduledFuture<?> periodicTaskHandle;

    public Test() {
        periodicTaskHandle = scheduler.scheduleWithFixedDelay(() -> {
            funcA("periodicRun-");
        }, 15, 15, TimeUnit.SECONDS);
    }

    private void funcA(String path) {
        LOGGER.info("Running the method " + path);
    }

    public void shutdown() {
        // 主动取消周期任务,禁止后续轮次调度,中断正在执行的任务
        if (periodicTaskHandle != null) {
            periodicTaskHandle.cancel(true);
        }
        scheduler.shutdown();
        try {
            // 等待现有任务执行终止
            if (!scheduler.awaitTermination(INITIAL_TERMINATION_WAIT_SEC, TimeUnit.SECONDS)) {
                scheduler.shutdownNow();
                // 等待任务响应中断后退出
                scheduler.awaitTermination(RETRY_TERMINATION_WAIT_SEC, TimeUnit.SECONDS);
            }
        } catch (InterruptedException ie) {
            scheduler.shutdownNow();
            Thread.currentThread().interrupt();
        }
        // shutdown流程完成后再打印日志,修正原来的位置错误
        funcA("shutdown-");
    }
}

注意:如果你的周期任务里存在阻塞操作(比如IO、锁等待、sleep),必须在捕获InterruptedException后退出任务逻辑,不要吞掉异常继续执行,否则就算发了中断信号任务也不会停止。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 03:42:18