ScheduledThreadPoolExecutor 是 Java 中用于执行定时任务和周期性任务的线程池实现类,它是 ThreadPoolExecutor 的子类,并实现了 ScheduledExecutorService 接口。它非常适合用来替代传统的 Timer 类,尤其是在高并发、需要调度多个任务的场景中。
一、核心功能
ScheduledThreadPoolExecutor 支持以下几种常见的任务调度方式:
1. 延迟执行一次任务
schedule(Runnable command, long delay, TimeUnit unit)
延迟一段时间后执行一次任务。
示例:
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
executor.schedule(() -> System.out.println("Task executed after 5 seconds"), 5, TimeUnit.SECONDS);
2. 延迟执行并返回结果
<T> ScheduledFuture<T> schedule(Callable<T> callable, long delay, TimeUnit unit)
适用于有返回值的任务。
示例:
ScheduledFuture<Integer> future = executor.schedule(() -> {
return 42;
}, 3, TimeUnit.SECONDS);
System.out.println(future.get()); // 输出:42
3. 固定频率执行(fixed-rate)
scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
从初始延迟开始,每隔固定时间执行一次任务。
如果任务执行时间超过间隔时间,下一次任务会在当前任务结束后立即执行,不会累积间隔。
示例:
executor.scheduleAtFixedRate(() -> {
System.out.println("Running every 2 seconds");
}, 0, 2, TimeUnit.SECONDS);
4. 固定延迟执行(fixed-delay)
scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
- 每次任务执行完成后,再等待固定时间才开始下一次任务。
- 不受任务执行时间的影响,保证两次任务之间至少间隔为 delay。
示例:
executor.scheduleWithFixedDelay(() -> {
try {
Thread.sleep(1000); // 模拟耗时操作
} catch (InterruptedException e) {}
System.out.println("Task completed, waiting next run...");
}, 0, 2, TimeUnit.SECONDS);
二、内部原理
1. 使用了 DelayedWorkQueue
这是一个基于堆实现的延迟队列(Delayed接口),每个任务都有一个触发时间。队列会根据任务的执行时间排序,优先级高的任务先执行。
2. 核心线程数 >= 1
即使没有任务提交,核心线程也会保持活跃状态,避免频繁创建销毁线程。
3. 支持多线程调度
不像 Timer 只有一个线程,ScheduledThreadPoolExecutor 可以使用多个线程来处理任务,提高并发能力。
三、常见使用场景
场景 | 示例 |
定时任务 | 每天凌晨清理日志 |
心跳检测 | 客户端与服务端维持连接的心跳包 |
缓存刷新 | 定期更新本地缓存数据 |
轮询检查 | 定期轮询数据库或文件变化 |
四、注意事项
正确关闭线程池
不要忘记在程序结束时关闭线程池,否则可能导致程序无法退出。
executor.shutdown(); // 等待所有已提交任务完成
// 或者
executor.shutdownNow(); // 尝试停止所有正在执行的任务
避免任务堆积
如果任务执行时间过长,而你又用了 scheduleAtFixedRate,可能会导致任务堆积。建议根据业务选择合适的调度策略。
异常处理
任务中抛出异常会导致后续任务不再执行,因此务必加上 try-catch。
executor.scheduleAtFixedRate(() -> {
try {
// your code
} catch (Exception e) {
e.printStackTrace();
}
}, 0, 1, TimeUnit.SECONDS);
五、对比 Timer 和 ScheduledThreadPoolExecutor
特性 | Timer | ScheduledThreadPoolExecutor |
单线程/多线程 | 单线程 | 多线程 |
异常影响 | 一个任务异常 → 整个Timer失效 | 一个任务异常不影响其他任务 |
并发能力 | 差 | 强 |
调度灵活性 | 有限 | 更灵活(支持 fixed-rate / fixed-delay) |
推荐程度 | 不推荐 | 推荐使用 |
六、完整示例代码
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class ScheduledThreadPoolExample {
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
// 延迟任务
executor.schedule(() -> System.out.println("After 3s"), 3, TimeUnit.SECONDS);
// 固定频率执行
ScheduledFuture<?> rateTask = executor.scheduleAtFixedRate(() -> {
System.out.println("Fixed Rate Task");
}, 0, 1, TimeUnit.SECONDS);
// 固定延迟执行
ScheduledFuture<?> delayTask = executor.scheduleWithFixedDelay(() -> {
System.out.println("Fixed Delay Task");
}, 0, 2, TimeUnit.SECONDS);
// 模拟运行一段时间后关闭
executor.schedule(() -> {
rateTask.cancel(false);
delayTask.cancel(false);
executor.shutdown();
}, 10, TimeUnit.SECONDS);
}
}
总结
功能 | 方法 |
延迟执行 | schedule(Runnable, delay, unit) |
延迟执行并返回结果 | schedule(Callable, delay, unit) |
固定频率 | scheduleAtFixedRate(...) |
固定延迟 | scheduleWithFixedDelay(...) |