ScheduledExecutorService 是 Java 中用于定时和周期性任务的线程池接口,比 Timer 更可靠、线程安全且支持多种调度方式;可通过 Executors 创建单线程或多线程调度器,推荐显式配置 ThreadFactory 和拒绝策略,并使用 ThreadPoolExecutor + ScheduledFuture 组合以增强可监控性;支持一次性延迟任务(schedule)和两种周期任务(fixed-delay 与 fixed-rate),需注意执行时间超期对调度的影响;关闭时须先 shutdown() 再 awaitTermination(),必要时 shutdownNow(),并确保在 finally 或 try-with-resources 中释放资源。

ScheduledExecutorService 是 Java 提供的专门用于定时和周期性任务的线程池接口,比直接用 Timer 更可靠、线程安全且支持多种调度方式。
创建 ScheduledExecutorService 实例
通常通过 Executors 工具类创建,最常用的是 ScheduledThreadPoolExecutor:
- 单线程调度器:
Executors.newSingleThreadScheduledExecutor()—— 适合串行执行、避免并发冲突的任务(如日志轮转) - 多线程调度器:
Executors.newScheduledThreadPool(3)—— 支持多个任务并行调度,适合独立、不相互依赖的定时作业
注意:生产环境建议显式指定 ThreadFactory 和拒绝策略,避免默认配置带来的隐患;也推荐优先使用 ThreadPoolExecutor + ScheduledFuture 的组合替代静态工厂方法,便于监控和管理。
提交一次性延迟任务
使用 schedule(Runnable command, long delay, TimeUnit unit) 在指定延迟后执行一次:
立即学习“Java免费学习笔记(深入)”;
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
service.schedule(() -> System.out.println("3秒后执行"), 3, TimeUnit.SECONDS);- 返回 ScheduledFuture<?>,可用于取消任务:
future.cancel(true) - 如果任务执行中被中断,cancel 的参数
mayInterruptIfRunning决定是否尝试中断正在运行的线程
提交周期性任务
两种常见周期调度方式:
-
固定延迟执行:
scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)上次任务结束到下次开始之间间隔固定时间。适合执行耗时不确定、需错开运行的任务(如清理临时文件) -
固定频率执行:
scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)按照固定时间间隔启动任务(从初始时间起算),不管上一次是否完成。适合严格节奏的场景(如每 5 秒采集一次指标)
⚠️ 注意:若任务执行时间超过周期,fixed-rate 可能导致任务堆积甚至线程饥饿;fixed-delay 则更稳健,但节奏不严格。
优雅关闭与资源释放
定时任务线程池不能像普通线程池那样简单调用 shutdown() 就完事:
- 先调用
shutdown()停止接收新任务 - 再用
awaitTermination(long timeout, TimeUnit unit)等待已调度任务完成(包括正在运行和等待执行的) - 必要时调用
shutdownNow()强制中断所有正在执行的任务(会返回未执行的 Runnable 列表) - 务必在 finally 或 try-with-resources 中确保关闭,避免 JVM 无法退出
不复杂但容易忽略 —— 忘记关闭会导致线程长期存活,影响应用生命周期管理。

















