简体   繁体   中英

Future.cancel() is not cancelling the scheduled execution of ScheduledExecutorService

I am scheduling a task as:

ScheduledExecutorService dataService = Executors.newScheduledThreadPool(1);
Future<?> dataTimerHandle = dataService.scheduleAtFixedRate(runnable, 100, freq, TimeUnit.MILLISECONDS);

This works fine without a flaw.

However, when a certain flag becomes true on user action, the task is no more required periodically, and needs to be executed just once. I then attempt cancelling the task and submitting it just once as follows:

if(!dynamicUpdate) {
    dataTimerHandle.cancel(true); 
    dataTimerHandle = dataService.submit(runnable);
}
else { //Reschedule again:
    dataTimerHandle = dataService.scheduleAtFixedRate(runnable, 100, freq, TimeUnit.MILLISECONDS);
}

But seems like the runnable is still executing periodically and cancel() is not working as expected. Is there an alternate strategy for this?

The problem is probably not in the Future's cancel() method. Here is a small runnable example that appears to be doing exactly what you want:

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);
    }

}

This is expected since you are sending the cancel command to the wrong handle. When you call service.submit() it returns a handle for the newly created future, and you can't use the very same handle to send cancel messages to future's created via other calls

Obviously you can shut down the executor service via sevice.shutdown() to not start any runnable submitted after a certain moment

我认为,future.cancel方法会中断RUNNING线程的线程,因此您需要在runnable类中捕获InterruptedException并仅返回即可。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM