Java中使用ScheduledExecutorService执行定时任务的核心是创建调度线程池、提交延迟或周期性任务并管理生命周期;推荐用Executors.newScheduledThreadPool(n)创建,按CPU密集型或I/O型合理设线程数,单任务用newSingleThreadScheduledExecutor(),需命名线程、避免内存泄漏,正确调用shutdown()或shutdownNow()关闭。

Java 中用 ScheduledExecutorService 执行定时任务,核心是创建调度线程池、提交带延迟或周期性执行的任务,再合理管理生命周期。
创建合适的 ScheduledExecutorService 实例
推荐使用 Executors.newScheduledThreadPool(n) 创建,避免直接用 new ThreadPoolExecutor(...) 手动构造。线程数根据任务类型决定:纯 CPU 密集型可设为 CPU 核心数;含 I/O 等待的可适当增加(如 2–4 倍核数)。单任务场景可用 Executors.newSingleThreadScheduledExecutor(),保证顺序执行且资源开销小。
- 不要用
Executors.newCachedThreadPool()或固定线程池替代,它们不支持调度方法 - 生产环境建议命名线程池,便于排查(通过
ThreadFactory设置线程名) - 避免在 Web 容器(如 Tomcat)中使用静态未关闭的实例,防止内存泄漏
提交一次性延迟任务
调用 schedule(Runnable command, long delay, TimeUnit unit) 即可。任务在指定延迟后执行一次,不重复。
- 延迟从调用时刻开始计算,不是从上一个任务结束开始
- 如果任务抛出未捕获异常,该任务终止,但不影响线程池继续调度其他任务
- 示例:
scheduler.schedule(() -> System.out.println("5秒后执行"), 5, TimeUnit.SECONDS);
提交周期性重复任务
有两种方式:scheduleAtFixedRate 和 scheduleWithFixedDelay,区别关键在“间隔起点”:
立即学习“Java免费学习笔记(深入)”;
- fixed-rate:按固定频率执行,下次执行时间 = 上次开始时间 + 周期。若任务耗时 > 周期,会“追赶”,可能连续触发
- fixed-delay:按固定间隔执行,下次执行时间 = 上次结束时间 + 延迟。更安全,适合耗时不确定的任务
- 示例(每 3 秒执行一次,每次执行完等 3 秒再下一次):
scheduler.scheduleWithFixedDelay(this::doWork, 0, 3, TimeUnit.SECONDS);
正确关闭调度器并处理残留任务
必须显式调用 shutdown() 或 shutdownNow(),否则 JVM 不会退出(因为线程池默认 daemon 为 false)。
-
shutdown():拒绝新任务,等待已提交任务完成(包括正在运行和队列中的) -
shutdownNow():尝试中断所有正在执行的任务,并返回未执行的任务列表 - 建议配合
awaitTermination()等待优雅关闭,超时后可强制 shutdownNow - 可在应用关闭钩子(
Runtime.getRuntime().addShutdownHook())中统一关闭


















