17370845950

在Java中如何使用ScheduledExecutorService调度任务
ScheduledExecutorService 提供了比 Timer 更强大的任务调度功能,可通过 Executors.newScheduledThreadPool 创建线程池,支持一次性延迟执行、固定延迟和固定速率的周期性任务调度,使用 schedule 返回的 ScheduledFuture 可取消任务,最后需调用 shutdown 关闭线程池以释放资源。

ScheduledExecutorService 是 Java 中用于调度延迟或周期性执行任务的工具,相比 Timer 和 TimerTask,它更灵活、功能更强,推荐在多线程环境下使用。下面介绍如何正确使用 ScheduledExecutorService 来调度任务。

创建 ScheduledExecutorService 实例

通过 Executors 工具类可以快速创建 ScheduledExecutorService:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);

这里创建了一个包含两个线程的调度线程池。你可以根据需要调整线程数量。如果是单线程场景,也可以使用 Executors.newSingleThreadScheduledExecutor()

调度一次性延迟任务

使用 schedule(Runnable command, long delay, TimeUnit unit) 方法可以在指定延迟后执行一次任务:

scheduler.schedule(() -> {
    System.out.println("任务在 5 秒后执行");
}, 5, TimeUnit.SECONDS);

这个任务会在 5 秒后由线程池中的某个线程执行,适用于延迟触发的场景,比如延迟发送通知。

调度周期性任务

有两种方式执行周期性任务:固定延迟和固定速率。

1. 固定延迟执行(scheduleWithFixedDelay)

任务执行结束后,等待指定延迟再执行下一次:

scheduler.scheduleWithFixedDelay(() -> {
    System.out.println("每 3 秒执行一次,从上一次结束开始计时");
}, 0, 3, TimeUnit.SECONDS);

适合任务执行时间可能波动的场景,能避免任务堆积。

2. 固定速率执行(scheduleAtFixedRate)

无论任务执行多久,尝试按照固定的周期执行(从开始时间算起):

scheduler.scheduleAtFixedRate(() -> {
    System.out.println("每 2 秒执行一次,从上一次开始计时");
}, 0, 2, TimeUnit.SECONDS);

如果任务执行时间超过周期,下一次会尽快执行,不会并发。适用于定时轮询等对时间精度要求较高的场景。

取消调度任务

调用 schedule 方法会返回一个 ScheduledFuture 对象,可用于取消任务:

ScheduledFuture future = scheduler.scheduleAtFixedRate(() -> {
    System.out.println("周期性任务");
}, 0, 1, TimeUnit.SECONDS);

// 在某个条件满足时取消任务
future.cancel(false); // 参数 false 表示不中断正在执行的任务

取消后任务将不再执行。若任务正在运行,false 会等待其完成,true 则尝试中断。

使用完 ScheduledExecutorService 后,记得调用 shutdown() 关闭线程池,避免资源泄漏:

scheduler.shutdown();
try {
    if (!scheduler.awaitTermination(60, TimeUnit.SECONDS)) {
        scheduler.shutdownNow();
    }
} catch (InterruptedException e) {
    scheduler.shutdownNow();
    Thread.currentThread().interrupt();
}

基本上就这些。掌握这几个核心方法,就能在 Java 中高效地调度任务了。注意合理设置线程数和任务周期,避免系统负载过高。