ScheduledThreadPoolExecutor
是 Java 中的一种线程池,它继承自 ThreadPoolExecutor
,并实现了 ScheduledExecutorService
接口。它用于调度和执行定时任务,支持延时执行和周期性执行。
相比于普通的 ThreadPoolExecutor
,ScheduledThreadPoolExecutor
提供了更多的定时任务调度功能,适用于执行需要按固定时间间隔、延时执行的任务。
1. 主要特点
- 延时执行:任务可以在指定的延时后执行。
- 周期执行:任务可以按照固定的周期反复执行。
- 线程池管理:继承自
ThreadPoolExecutor
,它能够有效管理线程池中的线程。 - 支持取消任务:你可以取消一个任务的执行。
2. 构造方法
ScheduledThreadPoolExecutor
提供了以下几种常用的构造方法:
public ScheduledThreadPoolExecutor(int corePoolSize);
public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory);
public ScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler);
public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler);
- corePoolSize:线程池的核心线程数。线程池的核心线程数大小决定了线程池在不忙时保留的线程数。
- threadFactory:自定义线程工厂,用于创建新线程。
- handler:拒绝执行任务时的处理策略。
3. 核心方法
ScheduledThreadPoolExecutor
提供了一些方法来安排任务的执行,包括延时执行、周期性执行等。
3.1 延时执行
ScheduledThreadPoolExecutor
可以调度任务在某个延迟之后执行。
- schedule():将任务安排在某个延时后执行一次。
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
Runnable task = () -> System.out.println("Task executed!");
executor.schedule(task, 5, TimeUnit.SECONDS); // 5秒后执行
上述代码将在 5 秒后执行任务 task
。
3.2 周期性执行
你可以让任务按照固定的时间间隔周期性执行。
- scheduleAtFixedRate():按照固定的频率执行任务。它指定了两次执行任务之间的时间间隔,但不会考虑任务执行的时间长度。
executor.scheduleAtFixedRate(() -> System.out.println("Fixed-rate task executed!"), 0, 10, TimeUnit.SECONDS);
上述代码将在立即启动任务后,每 10 秒执行一次任务。scheduleAtFixedRate
保证了两次任务之间的间隔时间是固定的。
- scheduleWithFixedDelay():与
scheduleAtFixedRate()
类似,但是它会考虑任务的执行时间。如果任务执行的时间较长,下一次任务会在上一次执行完毕之后再开始,并且两次任务之间的间隔是以执行时间为基准。
executor.scheduleWithFixedDelay(() -> System.out.println("Fixed-delay task executed!"), 0, 10, TimeUnit.SECONDS);
上述代码将在立即启动任务后,每次执行完任务后等待 10 秒再执行下一次任务。
3.3 调度周期性任务的区别
scheduleAtFixedRate()
:- 任务的开始时间是固定的间隔(例如,每 10 秒执行一次)。
- 即使任务的执行时间较长,也不会延迟下次执行。
scheduleWithFixedDelay()
:- 每次任务的开始时间是上一次任务执行完成后的固定延时(例如,每次任务执行完 10 秒后才开始下次执行)。
- 任务的执行时间会影响到下一次任务的调度。
4. 如何工作
- 任务调度:
ScheduledThreadPoolExecutor
继承了ThreadPoolExecutor
,所以它的任务执行过程与ThreadPoolExecutor
类似。调度线程池通过一个内部的调度器来管理任务的执行。调度器会定期检查是否有需要执行的任务。 - 延时任务:
当任务被安排延时执行时,调度器会将任务放入任务队列,并在指定的延迟时间后提交给线程池执行。 - 周期性任务:
周期性任务被安排后,调度器会根据任务的类型(FixedRate
或FixedDelay
)计算下次任务的执行时间,并将其提交给线程池。
5. 任务取消
你可以使用 ScheduledFuture
来取消已调度的任务。
- cancel():取消任务。
ScheduledFuture<?> future = executor.schedule(() -> System.out.println("Task executed!"), 5, TimeUnit.SECONDS);
future.cancel(false); // 取消任务
- get():获取任务的执行结果。
ScheduledFuture<?> future = executor.schedule(() -> System.out.println("Task executed!"), 5, TimeUnit.SECONDS);
future.get(); // 阻塞,直到任务执行完成
6. 常见应用场景
- 定时任务:比如定时清理缓存、定时报告生成、定时备份等。
- 周期性任务:比如定时轮询某个服务、定时检查任务执行情况等。
- 延时任务:比如延时发送通知、延时执行某些操作等。
7. 示例代码
import java.util.concurrent.*;
public class ScheduledThreadPoolExecutorExample {
public static void main(String[] args) {
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(2);
// 延时任务
executor.schedule(() -> System.out.println("Delayed Task Executed!"), 3, TimeUnit.SECONDS);
// 周期性任务:每 2 秒执行一次
executor.scheduleAtFixedRate(() -> System.out.println("Fixed-rate Task Executed!"), 1, 2, TimeUnit.SECONDS);
// 周期性任务:每次任务结束后等待 2 秒再执行
executor.scheduleWithFixedDelay(() -> System.out.println("Fixed-delay Task Executed!"), 1, 2, TimeUnit.SECONDS);
}
}
8. 注意事项
- 线程池的大小:
ScheduledThreadPoolExecutor
维护了一个核心线程池,因此你需要合理配置核心线程数。 - 任务的执行时间:对于周期性任务,若任务执行时间过长,可能导致任务间隔时间不准。因此,使用
scheduleWithFixedDelay
比较合适。 - 取消任务:尽量避免使用过多的
cancel()
操作,否则会影响性能。 - 拒绝策略:与
ThreadPoolExecutor
类似,ScheduledThreadPoolExecutor
也支持设置任务拒绝策略,如AbortPolicy
、DiscardPolicy
等。
9. 总结
ScheduledThreadPoolExecutor
是 Java 中非常强大的定时任务调度工具,它继承了 ThreadPoolExecutor
,并在其基础上提供了延时和周期性任务的执行功能。无论是单次延时任务,还是周期性任务,它都能够高效地进行调度和管理。掌握 ScheduledThreadPoolExecutor
的使用,可以帮助你更好地管理定时任务和周期性任务,适应多种实际应用场景。
发表回复