我不确定这是否是最好的方法,但这是我想出的一种工作方式。
您需要三种类型的任务:
- 必须定期运行的任务本身 - 重要任务
- 另一个将取消其执行的任务,从现在开始我将其称为 kill 任务。
- 提交要执行的重要任务的任务 - 提交任务,这是您将使用
ScheduledExecutorService 安排定期运行的任务
这个想法是,当你的重要任务开始执行时,它会安排 kill 任务在 5 秒后运行。为了实现这一点,它需要知道它的Future 实例。为此,它需要提交任务来进行提交并让它知道它的'Future。
这里是important task:
import java.time.LocalTime;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ImportantTask implements Runnable {
//that's just to make it easier to track what happens with each task
private static long NEXT_ID = 1;
//needed to schedule kill task
private final ScheduledExecutorService executorService;
private final long taskId;
private Future<?> thisTaskFuture;
//only needed to know when to cancel all tasks and end test
private CountDownLatch countDownLatch;
public ImportantTask(ScheduledExecutorService executorService) {
this.executorService = executorService;
this.taskId = NEXT_ID++;
}
@Override
public void run() {
//make half the tasks take too long
long executionTimeSeconds = this.taskId % 2 == 0 ? 6 : 4;
System.out.println(this.getLogMessage("started"));
CancelFutureTask cancelFutureTask = new CancelFutureTask(this.thisTaskFuture);
//this schedules the kill task for single execution, after 5 seconds delay
this.executorService.schedule(cancelFutureTask, 5, TimeUnit.SECONDS);
try {
//simulating long execution
Thread.sleep(executionTimeSeconds * 1_000);
} catch (InterruptedException exc) {
System.out.println(this.getLogMessage("interrupted"));
//might need to check Thread.currentThread().isInterrupted(), depends on your exact case
return;
} finally {
this.countDownLatch.countDown();
}
//the task is already finished, even if cancel is called, it has no effect
System.out.println(this.getLogMessage("finished"));
}
private String getLogMessage(String taskStatus) {
return String.format("Task with id - %d, %s at %s", this.taskId, taskStatus, LocalTime.now());
}
public void setThisTaskFuture(Future<?> thisTaskFuture) {
this.thisTaskFuture = thisTaskFuture;
}
public void setCountDownLatch(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
}
CountDownLatch 在这里只是为了在执行几次后更容易停止 main 方法,您可能不需要它。注意代码中的cmets。
kill task 很简单:
import java.util.concurrent.Future;
public class CancelFutureTask implements Runnable {
private final Future<?> future;
private final boolean mayInterrupt;
public CancelFutureTask(Future<?> future, boolean mayInterrupt) {
this.future = future;
this.mayInterrupt = mayInterrupt;
}
public CancelFutureTask(Future<?> future) {
this(future, true);
}
@Override
public void run() {
this.future.cancel(this.mayInterrupt);
}
}
它只是取消了Future,如果未来已经完成执行,则不会有任何影响。
还有submit task:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
public class SubmitNewImportantTask implements Runnable {
private final ScheduledExecutorService executorService;
private final CountDownLatch countDownLatch;
public SubmitNewImportantTask(ScheduledExecutorService executorService, CountDownLatch countDownLatch) {
this.executorService = executorService;
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
ImportantTask importantTask = new ImportantTask(this.executorService);
//obtain Future instance
Future<?> future = this.executorService.submit(importantTask);
//let the task know of its Future instance
importantTask.setThisTaskFuture(future);
importantTask.setCountDownLatch(this.countDownLatch);
}
}
提交important task执行,获取Future实例并设置在important task中。
以及我用于测试的主要方法。
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class FuturesMain {
public static void main(String[] args) throws Exception {
CountDownLatch count = new CountDownLatch(6);
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(10);
SubmitNewImportantTask submitTask = new SubmitNewImportantTask(executorService, count);
executorService.scheduleAtFixedRate(submitTask, 0, 10, TimeUnit.SECONDS);
count.await();
executorService.shutdown();
boolean allTerminated = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("All terminated - " + allTerminated);
}
}