我将任务安排为:
ScheduledExecutorService dataService = Executors.newScheduledThreadPool(1);
Future<?> dataTimerHandle = dataService.scheduleAtFixedRate(runnable, 100, freq, TimeUnit.MILLISECONDS);
这工作很好,没有任何缺陷。
然而,当某个标志在用户操作时变为true
时,就不再需要周期性地执行该任务,只需要执行一次。然后我尝试取消任务并提交一次,如下所示:
if(!dynamicUpdate) {
dataTimerHandle.cancel(true);
dataTimerHandle = dataService.submit(runnable);
}
else { //Reschedule again:
dataTimerHandle = dataService.scheduleAtFixedRate(runnable, 100, freq, TimeUnit.MILLISECONDS);
}
但看起来runnable仍在周期性执行,cancel()
没有按预期工作。有没有替代策略?
问题可能不在Future的cancel()
方法中。下面是一个可以运行的小例子,它似乎正是在做你想要的事情:
import java.util.concurrent.*;
public class CancelPeriodicTask {
public static void main(String[] args) {
ScheduledThreadPoolExecutor scheduler = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(1);
scheduler.setRemoveOnCancelPolicy(true);
try {
new CancelPeriodicTask().test(scheduler);
} catch (Exception e) {
e.printStackTrace();
} finally {
int openTasks = scheduler.shutdownNow().size();
println("Finished, open tasks: " + openTasks);
// openTasks will be 1 when RemoveOnCancelPolicy is false
// and the executor is closed within the scheduled task-period.
}
}
private static long sleepTime = 25L;
public void test(ScheduledThreadPoolExecutor scheduler) throws Exception {
// sleep 5 times at scheduled interval
SleepTask sleepTask;
ScheduledFuture<?> scheduledSleep = scheduler.scheduleAtFixedRate(sleepTask = new SleepTask(), 0, 2 * sleepTime, TimeUnit.MILLISECONDS);
sleepTask.sleepTimes.await();
println("Cancelling scheduledSleep. Done: " + scheduledSleep.isDone() + ", cancelled: " + scheduledSleep.isCancelled());
scheduledSleep.cancel(true);
Thread.sleep(2 * sleepTime);
println("Running sleepTask once.");
scheduler.submit(sleepTask);
Thread.sleep(2 * sleepTime);
scheduledSleep = scheduler.scheduleAtFixedRate(sleepTask, 0, 2 * sleepTime, TimeUnit.MILLISECONDS);
println("Re-scheduled scheduledSleep. Done: " + scheduledSleep.isDone() + ", cancelled: " + scheduledSleep.isCancelled());
Thread.sleep(5 * sleepTime);
println("Cancelling scheduledSleep. Done: " + scheduledSleep.isDone() + ", cancelled: " + scheduledSleep.isCancelled());
scheduledSleep.cancel(true);
}
class SleepTask implements Runnable {
public final CountDownLatch sleepTimes = new CountDownLatch(5);
public int sleepCount;
@Override public void run() {
println("Sleeping " + (++sleepCount));
try { Thread.sleep(sleepTime); } catch (Exception e) {
e.printStackTrace();
}
sleepTimes.countDown();
}
}
private static final long START_TIME = System.currentTimeMillis();
private static void println(String msg) {
System.out.println((System.currentTimeMillis() - START_TIME) + "t " + msg);
}
}
这是意料之中的事,因为您将cancel命令发送到了错误的句柄。当你调用service.submit()
时,它会返回一个新创建的future的句柄,并且你不能使用同一个句柄向通过其他调用创建的furt发送取消消息
显然,您可以通过sevice.shutdown()
关闭executor服务,以便在某个时刻之后不启动任何可运行的提交
我认为future.cocancel方法会中断线程RUNNING线程,因此您需要在可运行类&只是回归;