1. ScheduledExecutorService概述
ScheduledExecutorService 是 Java 中用于计划和执行定时任务的接口。它扩展了 ExecutorService 接口,专门用于调度在给定的延迟后运行的任务或定期执行的任务。ScheduledExecutorService 提供了更强大的控制能力和灵活性来处理定时任务,比传统的 Timer 和 TimerTask 更加可靠和高效。它是基于线程池的调度执行器,专门用于管理和执行并发任务。类ScheduledExecutorService的主要作用就是可以将定时任务与线程池功能结合使用。
1.1 优点
• 高并发控制:适用于需要同时执行多个任务的场景,如定时轮询多个服务或资源。
• 资源管理:通过线程池管理并发任务,避免频繁创建和销毁线程带来的开销。
• 任务隔离:多个任务并行执行,彼此之间互不干扰,提高系统的可靠性和响应性。
1.2 应用场景
1. 延迟执行任务:可以在指定的延迟时间之后执行一次任务。
2. 定期执行任务:可以按照固定的时间间隔(周期)重复执行任务,无论是固定速率执行还是固定延迟执行。
3. 取消任务:支持任务的取消和终止功能,可以中断尚未执行的任务或已在执行中的任务。
1.3 关于并发
1. 线程池管理:ScheduledExecutorService 依赖线程池来执行任务。线程池的大小和类型可以在创建 ScheduledExecutorService 时指定,如使用 Executors.newScheduledThreadPool(int corePoolSize) 创建一个具有固定线程数量的调度器。这意味着多个任务可以同时运行,从而实现并发执行。
2. 任务调度与并发执行:它可以调度多个任务并发执行。例如,当你使用 scheduleAtFixedRate 或 scheduleWithFixedDelay 方法时,如果调度的间隔足够短且线程池中的线程足够多,多个任务将会并发运行。
3. 线程安全性:ScheduledExecutorService 内部实现了任务的调度和执行,这些操作是线程安全的。这意味着多个任务可以安全地被调度和执行,而不必担心调度器本身出现线程同步问题。
4. 控制并发数量:通过配置线程池的大小,ScheduledExecutorService 可以限制并发任务的数量。如果线程池的线程数量小于调度的任务数量,任务将会排队等待空闲线程执行。这提供了一种控制并发度的机制。
5. 异常处理:ScheduledExecutorService 也提供了良好的异常处理机制。与传统的 Timer 不同,一个任务中的异常不会影响其他任务的执行,从而提高了并发任务的健壮性。
1.4 ScheduledExecutorService核心方法
• schedule(Runnable command, long delay, TimeUnit unit): 在指定的延迟后执行一次任务。
• schedule(Callable<V> callable, long delay, TimeUnit unit): 在指定的延迟后执行任务并返回结果。
• scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit): 以固定的速率定期执行任务,第一个任务延迟 initialDelay 执行,之后每隔 period 时间间隔执行一次。
• scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit): 以固定的延迟时间执行任务,第一个任务延迟 initialDelay 执行,每个后续任务在前一个任务完成后的 delay 时间后执行。
接口ScheduledExecutorService的核心方法列表如图:
1.5 接口继承及实现关系如图:
从上图看到,类ScheduledThreadPoolExecutor是ScheduledExecutorService的实现类,ScheduledThreadPoolExecutor的API结构如图:
2. ScheduledThreadPoolExecutor
类ScheduledThreadPoolExecutor是ScheduledExecutorService的实现类,ScheduledThreadPoolExecutor的getQueue() 和 remove() 方法使用代码示例:
. getQueue() 方法
• 来源: getQueue() 是 ScheduledThreadPoolExecutor 类的一个方法,而不是 ScheduledExecutorService 接口本身的方法。
• 功能: getQueue() 返回一个 BlockingQueue<Runnable>,该队列包含所有等待执行的任务。这些任务已经被调度但尚未开始执行,或者被延迟执行。
• 用途:
• 查看队列中的任务: 可以用来检查当前哪些任务在等待执行,了解任务调度的状态。
• 管理和监控: 适合用于监控任务队列的长度,以评估调度器的负载。
• 任务操作: 可以手动操作队列中的任务,例如查询、遍历或取消特定任务。
示例:
import java.util.concurrent.*;
public class GetQueueExample {
public static void main(String[] args) {
ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(2);
// 定义任务
Runnable task1 = () -> System.out.println("Task 1 executed");
Runnable task2 = () -> System.out.println("Task 2 executed");
// 调度任务
scheduler.schedule(task1, 5, TimeUnit.SECONDS);
scheduler.schedule(task2, 10, TimeUnit.SECONDS);
// 获取等待执行的任务队列
BlockingQueue<Runnable> queue = scheduler.getQueue();
System.out.println("Number of tasks in the queue: " + queue.size()); // 输出队列中的任务数
scheduler.shutdown();
}
}
remove() 方法
• 来源: remove() 方法也属于 ScheduledThreadPoolExecutor,用于从任务队列中移除指定的任务。
• 功能: 通过 remove() 方法可以从任务队列中删除一个尚未执行的任务。它只能移除 Runnable 类型的任务,不会影响已经开始执行或已经完成的任务。
• 用途:
• 取消未执行的任务: 用于取消那些不再需要执行的任务,释放资源。
• 调整任务队列: 有时可能需要在运行时根据新条件调整任务队列,remove() 提供了直接的任务移除功能。
示例:
import java.util.concurrent.*;
public class RemoveTaskExample {
public static void main(String[] args) {
ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(2);
// 定义任务
Runnable task1 = () -> System.out.println("Task 1 executed");
Runnable task2 = () -> System.out.println("Task 2 executed");
// 调度任务
ScheduledFuture<?> future1 = scheduler.schedule(task1, 5, TimeUnit.SECONDS);
ScheduledFuture<?> future2 = scheduler.schedule(task2, 10, TimeUnit.SECONDS);
// 从队列中移除 task2
boolean removed = scheduler.remove(task2);
System.out.println("Task 2 removed: " + removed); // 输出是否成功移除任务2
// 观察剩余队列
System.out.println("Number of tasks in the queue after removal: " + scheduler.getQueue().size());
scheduler.shutdown();
}
}
总结
• getQueue(): 用于获取当前等待执行的任务队列,方便监控和管理。
• remove(): 从调度队列中移除未执行的任务,提供任务队列的动态调整能力。
这些方法为 ScheduledThreadPoolExecutor 提供了更高的灵活性和控制能力,有助于在需要动态管理任务队列的应用场景中有效发挥作用。