Future.cancel()不会取消ScheduledExecutorService的计划执行

时间:2015-03-21 10:57:36

标签: java multithreading concurrency executorservice java.util.concurrent

我正在安排一项任务:

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()无法按预期工作。 是否有替代策略?

3 个答案:

答案 0 :(得分:1)

这是预期的,因为您将cancel命令发送到错误的句柄。当您致电service.submit()时,它会返回新创建的未来的句柄,并且您无法使用相同的句柄将取消消息发送给通过其他来电创建的未来

显然,您可以通过sevice.shutdown()关闭执行程序服务,以便在某个时刻之后无法启动任何可运行的

答案 1 :(得分:1)

问题可能不在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);
    }

}

答案 2 :(得分:0)

我认为,future.cancel方法会中断RUNNING线程的线程,因此您需要捕获runnable类中的InterruptedException。回来;