一、背景
在Java中,ScheduledExecutorService
是一个用于处理需要定时或周期性执行的任务的强大工具。如果你想要重复地创建和停止周期性任务,你可以使用ScheduledExecutorService
的scheduleAtFixedRate
或scheduleWithFixedDelay
方法,并且结合取消任务的能力来实现。
以下是一个简单的例子,展示了如何重复创建和停止周期性任务:
import java.util.concurrent.*;
public class ScheduledTaskExample {
private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private ScheduledFuture<?> future; // 用于保存周期性任务的句柄
// 启动周期性任务
public void startPeriodicTask(Runnable task, long initialDelay, long period, TimeUnit unit) {
// 如果之前已经有任务在运行,先取消它
cancelPeriodicTask();
// 提交新的周期性任务
future = scheduler.scheduleAtFixedRate(task, initialDelay, period, unit);
}
// 停止周期性任务
public void stopPeriodicTask() {
// 取消任务
if (future != null && !future.isCancelled()) {
future.cancel(true); // 传入true表示如果任务正在执行则中断它
future = null; // 清空future引用
}
}
// 取消周期性任务(如果需要的话,你可以将这个方法合并到stopPeriodicTask中)
private void cancelPeriodicTask() {
if (future != null && !future.isCancelled()) {
future.cancel(false); // 如果任务正在执行,则不中断它,只是停止后续的执行
}
}
public static void main(String[] args) {
ScheduledTaskExample example = new ScheduledTaskExample();
// 示例任务
Runnable task = () -> {
System.out.println("周期性任务执行中..." + System.currentTimeMillis());
};
// 启动周期性任务,初始延迟1秒,之后每隔2秒执行一次
example.startPeriodicTask(task, 1, 2, TimeUnit.SECONDS);
// 等待一段时间来观察任务执行
try {
Thread.sleep(10000); // 等待10秒
} catch (InterruptedException e) {
e.printStackTrace();
}
// 停止周期性任务
example.stopPeriodicTask();
// 你可以再次启动任务...
// example.startPeriodicTask(task, 1, 2, TimeUnit.SECONDS);
// 最后,关闭调度器(如果你确定不再需要它)
example.shutdownScheduler();
}
// 关闭调度器
public void shutdownScheduler() {
if (scheduler != null && !scheduler.isShutdown()) {
scheduler.shutdown(); // 这不会立即停止正在执行的任务
try {
if (!scheduler.awaitTermination(60, TimeUnit.SECONDS)) {
scheduler.shutdownNow(); // 强制停止所有正在执行的任务
}
} catch (InterruptedException ie) {
scheduler.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
}
在这个例子中,startPeriodicTask
方法用于启动周期性任务,它首先取消任何正在运行的任务(如果有的话),然后提交一个新的任务。stopPeriodicTask
方法用于停止当前周期性任务。注意,future.cancel(true)
会尝试中断正在执行的任务(如果任务支持中断的话),而future.cancel(false)
则只会停止后续的执行。
最后,shutdownScheduler
方法用于关闭ScheduledExecutorService
。这在实际应用中是很重要的,因为如果你不再需要调度器,就应该关闭它以释放资源。请注意,关闭调度器并不会立即停止正在执行的任务,它会等待所有任务完成(或者你可以调用shutdownNow
来强制停止它们)。
二、案例
private ScheduledExecutorService executor;
private ScheduledFuture<?> future;
private void excDurations() {
// 创建线程池
// executor = Executors.newScheduledThreadPool(1);
// executor = Executors.newSingleThreadScheduledExecutor();
// future = executor.scheduleAtFixedRate(runnable, 0, 30, TimeUnit.SECONDS);
// 如果前一个任务还在运行,先取消它
if (future != null && !future.isCancelled()) {
future.cancel(true); // 如果任务正在执行,则可能无法立即停止
}
if (executor != null) {
// 关闭executor服务
executor.shutdownNow();
try {
// 等待服务关闭
if (!executor.awaitTermination(200, TimeUnit.MILLISECONDS)) {
System.out.println("ExecutorService did not terminate in the given time.");
}
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt(); // 重新中断线程
}
}
executor = null;
// executor = Executors.newScheduledThreadPool(1);
executor = Executors.newSingleThreadScheduledExecutor();
future = executor.scheduleAtFixedRate(runnable, 0, 8, TimeUnit.HOURS);
}