ScheduledExecutorService是专为周期性或延迟执行任务设计的线程池接口,支持schedule、scheduleAtFixedRate和scheduleWithFixedDelay三种调度方式,需显式关闭以避免JVM无法退出。

在 Java 中,ScheduledExecutorService 是 ExecutorService 的子接口,专为**周期性或延迟执行任务**设计。它天然支持定时调度,无需依赖第三方库(如 Quartz),也比手动用 Timer 更健壮、线程安全、可扩展。
用 ScheduledThreadPoolExecutor 创建调度线程池
最常用的方式是通过 Executors.newScheduledThreadPool(int corePoolSize) 获取实例。这个工厂方法返回的是 ScheduledThreadPoolExecutor 的实现,底层仍基于工作线程池,但增加了任务队列(基于最小堆的延迟队列 DelayedWorkQueue)来管理定时逻辑。
建议显式指定线程数(不推荐无界线程池),例如:
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);- 若任务间无依赖且 CPU 密集,线程数通常设为
Runtime.getRuntime().availableProcessors() - 若多为 I/O 等待型任务(如 HTTP 调用、DB 查询),可适当调高(如 4–8)
三种核心调度方式及使用场景
ScheduledExecutorService 提供三个关键方法,区别在于触发时机和重复逻辑:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
-
schedule(Runnable command, long delay, TimeUnit unit):延迟执行一次,比如“5 秒后发告警邮件” -
scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit):固定频率执行——从首次执行开始计时,每period时间触发一次(即使上次未完成,也可能并发执行)。适合心跳上报、状态采样等对时间精度要求高的场景 -
scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit):固定延时执行——每次执行完后,再等待delay时间才启动下一次。适合有状态清理、资源回收类任务,避免任务堆积
正确关闭调度器与异常处理
调度器不会自动终止,必须主动关闭,否则 JVM 无法退出。标准做法是:
- 调用
scheduler.shutdown()停止接收新任务,已入队的定时任务仍会执行 - 配合
scheduler.awaitTermination(long timeout, TimeUnit unit)等待完成,超时后可调用scheduler.shutdownNow()尝试中断运行中任务 - 务必在
finally或try-with-resources(JDK 19+)中执行关闭逻辑
注意:任务内未捕获的异常会导致该任务后续不再执行(scheduleAtFixedRate 等会静默终止)。应在 Runnable 内部加 try-catch,或使用 Thread.setDefaultUncaughtExceptionHandler 做兜底。
实际小例子:每 3 秒打印一次系统时间(带关闭控制)
(简化版,生产环境建议封装成 Bean 并交由 Spring 管理生命周期)
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() -> {
try {
System.out.println("当前时间: " + LocalDateTime.now());
} catch (Exception e) {
// 防止单次异常导致整个调度停止
e.printStackTrace();
}
}, 0, 3, TimeUnit.SECONDS);
// …… 业务运行一段时间后
Thread.sleep(15_000);
scheduler.shutdown();
if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
scheduler.shutdownNow();
}
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










