ScheduledExecutorService: How can I wait for cancelled tasks to finish? - java

I have scheduled some tasks in a ScheduledExecutorService. On shutdown, I'd like to cancel them, and release a database lock once they are all done.
How can I wait for the cancelled tasks to finish processing?
Attempted solutions
according to my tests, future.cancel() does not block until the task has stopped executing
invoking future.get() after future.cancel() results in an immediate CancelledExecutionException
I'd rather not wait for shutdown of the entire executor, as it is shared among components

How can I wait for the cancelled tasks to finish processing?
The problem with this is that cancellation is done on a best effort basis. The javadoc states
Attempts to cancel execution of this task. This attempt will fail if
the task has already completed, has already been cancelled, or could
not be cancelled for some other reason.
Typically, cancellation is implemented with interruption and interruption is a convention. Nothing guarantees that it will be implemented correctly. So even if you do send a cancel, nothing guarantees that the underlying task (if already running) will fulfill the cancellation.
There's no reliable way to implement your use case.

Related

Mixture of shutdown() and shutdownNow()

ScheduledExecutorService inherits two methods from the ExecutorService, shutdown() and shutdownNow(). The difference between them:
shutdown initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted. Invocation has no additional effect if already shut down.
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.
Now I want to halt processing of waiting tasks while I don't want to interrupt currently executing tasks. I can't interrupt the threads because third party libraries are involved and they don't deal well with interrupts :-( But I need to cancel scheduled tasks, that are not currently executing since most of them are scheduled in an hour or so.
What's the best way to deal with this? What options Do I have?
Sounds like calling setExecuteExistingDelayedTasksAfterShutdownPolicy(false) on your executor should do the trick:
Sets the policy on whether to execute existing delayed tasks even when
this executor has been shutdown. In this case, these tasks will only
terminate upon shutdownNow, or after setting the policy to false when
already shutdown. This value is by default true.
Since it's true by default, these tasks are executed. If you set it to false, they shouldn't be executed any more. This shouldn't be confused with submitted tasks which the docs you quote refer to. They are just waiting in the queue to be executed right away, when there is a free worker.

RabbitMQ – Cancel consumer.nextDelivery while it's waiting for a response

Is it possible with the RabbitMQ amqp-client library to cancel a nextDelivery? I have a thread that has already called consumer.nextDelivery(), and this call is waiting for a response from the queue. What I want is to stop this from another thread. channel.basicCancel will cancel only after the current nextDelivery call has returned, which is not exactly what I want, because the application is in a state where it can't do anything with the received delivery.
I've been searching for a solution to this for a while, and I'm at the point where I think I'm misunderstanding something about RabbitMQ, because I get no search results that match my problem.
What I want is to stop this from another thread
Personal advice: don't do it.
From the information gathered in the comments, it appears that you are separating the message receival from its treatment. My suggestion is to merge both; and use an ExecutorService to wrap them both.
When you need to shut the whole thing down, call .shutDown() on the ExecutorService: it means that no other task can be submitted to that execution.
As the receival/treatment process is now merged, it means you can never have a state in which a message is received but cannot be treated anymore.
I am not sure if this would work but try to use shutdownNow() of ExecutorService:
private ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(new Runnable()
{
#Override
public void run()
{
// ...
Message m = consumer.nextDelivery();
// ...
}
});
executor.shutdownNow();
ShutdownNow()'s javadoc states:
Attempts to stop all actively executing tasks, halts the processing of
waiting tasks, and returns a list of the tasks that were awaiting
execution. This method does not wait for actively executing tasks to
terminate. Use awaitTermination to do that.
There are no guarantees beyond best-effort attempts to stop processing
actively executing tasks. For example, typical implementations will
cancel via Thread.interrupt(), so any task that fails to respond to
interrupts may never terminate.

With a Java ExecutorService, how do I complete actively executing tasks but halt the processing of waiting tasks?

I am using an ExecutorService (a ThreadPoolExecutor) to run (and queue) a lot of tasks. I am attempting to write some shut down code that is as graceful as possible.
ExecutorService has two ways of shutting down:
I can call ExecutorService.shutdown() and then ExecutorService.awaitTermination(...).
I can call ExecutorService.shutdownNow().
According to the JavaDoc, the shutdown command:
Initiates an orderly shutdown in which previously submitted
tasks are executed, but no new tasks will be accepted.
And the shutdownNow command:
Attempts to stop all actively executing tasks, halts the
processing of waiting tasks, and returns a list of the tasks that were
awaiting execution.
I want something in between these two options.
I want to call a command that:
a. Completes the currently active task or tasks (like shutdown).
b. Halts the processing of waiting tasks (like shutdownNow).
For example: suppose I have a ThreadPoolExecutor with 3 threads. It currently has 50 tasks in the queue with the first 3 actively running. I want to allow those 3 active tasks to complete but I do not want the remaining 47 tasks to start.
I believe I can shutdown the ExecutorService this way by keeping a list of Future objects around and then calling cancel on all of them. But since tasks are being submitted to this ExecutorService from multiple threads, there would not be a clean way to do this.
I'm really hoping I'm missing something obvious or that there's a way to do it cleanly.
Thanks for any help.
I ran into this issue recently. There may be a more elegant approach, but my solution is to first call shutdown(), then pull out the BlockingQueue being used by the ThreadPoolExecutor and call clear() on it (or else drain it to another Collection for storage). Finally, calling awaitTermination() allows the thread pool to finish what's currently on its plate.
For example:
public static void shutdownPool(boolean awaitTermination) throws InterruptedException {
//call shutdown to prevent new tasks from being submitted
executor.shutdown();
//get a reference to the Queue
final BlockingQueue<Runnable> blockingQueue = executor.getQueue();
//clear the Queue
blockingQueue.clear();
//or else copy its contents here with a while loop and remove()
//wait for active tasks to be completed
if (awaitTermination) {
executor.awaitTermination(SHUTDOWN_TIMEOUT, TimeUnit.SECONDS);
}
}
This method would be implemented in the directing class wrapping the ThreadPoolExecutor with the reference executor.
It's important to note the following from the ThreadPoolExecutor.getQueue() javadoc:
Access to the task queue is intended primarily for debugging and
monitoring. This queue may be in active use. Retrieving the task queue
does not prevent queued tasks from executing.
This highlights the fact that additional tasks may be polled from the BlockingQueue while you drain it. However, all BlockingQueue implementations are thread-safe according to that interface's documentation, so this shouldn't cause problems.
The shutdownNow() is exactly what you need. You've missed the 1st word Attempts and the entire 2nd paragraph of its javadoc:
There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.
So, only tasks which are checking Thread#isInterrupted() on a regular basis (e.g. in a while (!Thread.currentThread().isInterrupted()) loop or something), will be terminated. But if you aren't checking on that in your task, it will still keep running.
You can wrap each submitted task with a little extra logic
wrapper = new Runnable()
public void run()
if(executorService.isShutdown())
throw new Error("shutdown");
task.run();
executorService.submit(wrapper);
the overhead of extra checking is negligible. After executor is shutdown, the wrappers will still be executed, but the original tasks won't.

How can I get the jobs that are in execution in a ScheduledThreadPoolExecutor?

I need to force the release of resources when a task is interrupted. For that, I implemented this solution. But with this, when I call shutdown() all the task in the ScheduledThreadPoolExecutor.getQueue() are forced correctly, but some of my jobs kept the resources. I checked very well the behavior and I figured out this: when a task is in execution, he is not present in the ScheduledThreadPoolExecutor queue (I know it sounds obvious). The problem is that I need to force the release of resources for all the jobs (in the queue or in execution)
So, How can I get the jobs that are in execution? Do you have a better idea?
You can maintain a list of all the Future's you create when you submit the jobs.
Use this list to cancel all futures.
Don't you want to call
executor.shutdownNow()
that will attempt to cancel currently running tasks (using Thread.interrupt so you'll need to implement an 'interruption policy' in each task that uses the interrupt flag).
from the javadoc
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. For example, typical implementations will cancel via Thread.interrupt, so any task that fails to respond to interrupts may never terminate.
This will return a list of waiting tasks, so you can always put this back onto a 'wait list' rather than loose them completely. You might also want follow that up with an 'await termination' to avoid run away code. For example, executor.awaitTermination(...).
tempus-fugit has some handy classes for handling this. You just call
shutdown(executor).waitingForShutdown(millis(400));
see here for details.
Also, the solution you outline in the blog post; I'm not sure if that's quite right. Future.cancel will only stop the task from being scheduled. If you were to update the example in the blog to allow interruption (ie cancel(true), it'd be equivalent (more or less) with the shutdownNow. That is to say, it will call interrupt on the underlying task which (if you've implemented an interruption policy) will stop it processing. As for cleaning up after interruption, you just need to make sure that you handle that appropriately within the interruption policy implementation. The upshot is that I think you can cancel and cleanup correctly using shutdownNow (or cancel(true))

Require FutureTask to be started before cancelled

In my Callable code I use signaling to notify multiple ending behaviours to another thread. The Callable objects are queued up with FutureTasks in an Executor. They may also be cancelled after being queued up.
Now, my problem is that I rely on the tasks atleast being started for my signaling to work, but it looks like the Executor just skips a task if it's been marked as canceled before it got a chance to run it.
So, is there a way to garantee that a task is always started, and always cancelled (by InterruptedException) while running.
Also, can you check if a task has not started but failed?
You can probably subclass FutureTask class and override its done() method to perform the signalling. According to the documentation, this method should be called even if the task has been cancelled.

Categories