scheduledthreadpoolexecutor 是 java 中用于定时和周期性任务的线程池,继承 threadpoolexecutor 并实现 scheduledexecutorservice,支持延迟执行、固定频率/固定延时调度,比 timer 更可靠。

ScheduledThreadPoolExecutor 是 Java 中专门用于执行定时和周期性任务的线程池,它继承自 ThreadPoolExecutor,实现了 ScheduledExecutorService 接口。相比普通线程池,它支持延迟执行、固定频率/固定延时周期执行等能力,是替代传统 Timer 的更可靠选择(避免单线程故障导致所有任务停摆)。
创建 ScheduledThreadPoolExecutor 实例
推荐通过 Executors.newScheduledThreadPool(int corePoolSize) 工厂方法创建,内部即返回 ScheduledThreadPoolExecutor 实例:
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
// 或显式构造(更可控,例如指定拒绝策略)
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(
2,
new ThreadPoolExecutor.CallerRunsPolicy() // 可选:自定义拒绝策略
);
注意:不要用 Executors.newSingleThreadScheduledExecutor() 来替代多线程场景,它底层只有一个线程,一个任务阻塞会拖慢后续所有定时任务。
提交定时任务的三种主要方式
核心方法都带时间单位参数,务必注意单位准确性(常用 TimeUnit.SECONDS 或 TimeUnit.MILLISECONDS):
-
schedule(Runnable command, long delay, TimeUnit unit):延迟一次执行,例如 3 秒后打印日志 -
scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit):固定速率执行——从首次执行开始,每 period 时间触发一次(即使前次未结束,也可能并发执行) -
scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit):固定延迟执行——每次执行完后,等待 delay 时间再执行下一次(严格串行,更安全)
示例:
scheduler.schedule(() -> System.out.println("5秒后执行一次"), 5, TimeUnit.SECONDS);
scheduler.scheduleAtFixedRate(
() -> System.out.println("每2秒执行(可能重叠)"),
0, 2, TimeUnit.SECONDS
);
scheduler.scheduleWithFixedDelay(
() -> {
try { Thread.sleep(1500); } catch (InterruptedException e) {}
System.out.println("执行完等1秒再继续");
},
0, 1, TimeUnit.SECONDS
);
取消任务与优雅关闭
每个 schedule 方法返回 ScheduledFuture>,可用于取消:
-
future.cancel(true):尝试中断正在运行的任务(需任务本身响应中断) - 若任务已开始且无法中断(如无检查
Thread.interrupted()),cancel 仅阻止后续执行
关闭线程池时建议组合使用:
scheduler.shutdown(); // 停止接收新任务,但会完成已提交任务
try {
if (!scheduler.awaitTermination(10, TimeUnit.SECONDS)) {
scheduler.shutdownNow(); // 强制中断运行中任务
}
} catch (InterruptedException e) {
scheduler.shutdownNow();
Thread.currentThread().interrupt();
}
常见注意事项
- 任务抛出未捕获异常会导致该任务线程终止,但线程池其他线程不受影响;建议在 Runnable/Callable 内部加 try-catch
- 周期任务不支持动态修改执行周期,如需调整,应先 cancel 原任务,再重新 schedule
- 慎用
scheduleAtFixedRate执行耗时不稳定的操作,可能引发任务堆积甚至 OOM - 如果只是单次延迟任务且无需复用线程池,考虑直接用
CompletableFuture.delayedExecutor更轻量
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











