Question

I have a task which requires me to schedule tasks and remove them when a certain event occurs. I'm using a ScheduledThreadPoolExecutor to schedule the tasks, that's pretty straightforward. But, I found two ways to cancel the pending items, both of them look a bit odd.

I'm curious if any of them is at production quality. If neither of them, then what do you suggest?

Here is a skeleton of what I do:

private final ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(1);

public void doStuff() {
    //...
    scheduler.schedule(new Runnable() {/*...*/}, 10, TimeUnit.MILISECONDS)
}

public void actOnEvent() {
    cancelPendingItems();
    doMoreStuff();
}

public void cancelPendnigItems() {
    // TODO implement me
}

This is candidate 1:

public void cancelPendingItems() {
    scheduler.getQueue().clear();
}

This is candidate 2:

public void cancelPendingItems() {
    for (Runnable task : scheduler.getQueue()) {
        scheduler.remove(task);
    }
}

Both look like a hack to me because they depend on the ScheduledThreadPoolExecutor.queue property which isn't specified in the ScheduledExecutor interface. I'm a bit worried that I might violate an invariant of ScheduledThreadPoolExecutor and I will detect it too late.

So, are these snippets going to do what I want them to do? Are there any better/cleaner ways to do it?

Was it helpful?

Solution

Note that ScheduledExecutorService.schedule returns a ScheduledFuture. Just store these and when your cancel method is called, use the cancel method on the stored futures to cancel their future iterations.

OTHER TIPS

I would use a List<Future>:

private final List<Future> futures = ...

public void doStuff() {
    futures.add(scheduler.schedule(new Runnable() {/*...*/}, 10,
        TimeUnit.MILISECONDS));
}

public void cancelPendingItems() {
    for(Future future: futures)
        future.cancel(true);
    futures.clear();
}

Future.cancel(boolean mayInterruptIfRunning)

Attempts to cancel execution of this task. This attempt will fail if the task has already completed, already been cancelled, or could not be cancelled for some other reason. If successful, and this task has not started when cancel is called, this task should never run. If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task.

Or you can also use ScheduledThreadPoolExecutor#shutdownNow

Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.

There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. This implementation cancels tasks via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.

So you need to handle InterruptedException to allow safe exit of threads which are being canceled.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top