Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 324
abksrv Avatar asked Mar 21 '15 10:03

abksrv


2 Answers

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

}
like image 115
vanOekel Avatar answered Sep 18 '22 17:09

vanOekel


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

like image 33
Raffaele Avatar answered Sep 19 '22 17:09

Raffaele