How to be sure threads are cleaned up - java

I have a method producer.postMessage(message) which sends a message to some queue. If for some reason the message could not be sent in a period of time I want this task to be canceled. I came up with the implementation below. My question is if there is an interrupt can I be sure the Future task/ executor service are all shutdown and if not what changes need to be made to make this working without any threads not being terminated.
Thanks a lot
public void postMessage(final Object object)
{
LOG.debug("postMessage object " + object.getClass().getSimpleName());
Message message = new Message("task", 10, object);
try
{
ExecutorService ex = Executors.newSingleThreadExecutor();
Future<?> f = ex.submit(new Runnable()
{
public void run()
{
producer.postMessage(message);
LOG.debug("Finished sending message for " + object.getClass().getSimpleName());
}
});
f.get(5, TimeUnit.SECONDS);
ex.shutdown();
}
catch (InterruptedException | ExecutionException | TimeoutException e)
{
LOG.error("Could not deliver message to the queue, Check AMQ is running");
}
}

The shutdown() method on an Executor will stop it from accepting new tasks, but attempts to complete the running tasks. You should use method shutdownNow() to have the Executor request that currently running tasks are stopped.
This may not be necessary however, if you use method cancel(boolean mayInterruptIfRunning) on the Future object. f.get(5, TimeUnit.SECONDS) will wait at most 5 seconds for completion of the tasks before returning. Since you submit a Runnable rather than a Callable, the return will always be null; Runnables can't return a result, while Callables can. What you can do is call isDone() on the Future after the get with a 5 second timeout, and if it returns false, it means the tasks has not completed. In that case you can then call cancel(true) on the Future to attempt to cancel the task. The true argument indicates that you'll allow the Future to interrupt the thread if it is running. You may want to catch InterruptedExceptions in your Runnable and log them. Note however that not every call may respond to interrupt requests (for example, some I/O operations may not, while a lot of Java NIO stuff does).
Calling the shutdown on the executor may no longer be necessary, since it's only used for a single task and should have no other waiting or running tasks, but it's probably still good form.
So your code would become:
f.get(5, TimeUnit.SECONDS);
if (!f.isDone())
f.cancel(true);
ex.shutdown();

Related

Moving a task to a separate thread, avoid duplication while task running & proper use of Executors + Future

We have a glue component between legacy code and current code. Essentially the whole legacy application is single threaded and has horrible issues where a ui refresh for a single instruction can happen 5 to 8 times.
I want to publish an async message after the first update request happens +2 seconds.
Let's not get stuck on the why, this is not what I want to really do, but I have to understand how to at least do this so I can implement a real solution.
Runnable task = () -> {
try {
TimeUnit.SECONDS.sleep(2);
messageBus.publishAsynch(new LegacyUiUpdateEvent());
} catch (InterruptedException e) {
// TODO Log something
Thread.currentThread().interrupt();
}
};
#Override
public void update(Observable arg0, Object arg1) {
ExecutorService executor = Executors.newSingleThreadExecutor();
if (futureTask == null || futureTask.isDone()) {
futureTask = executor.submit(task);
try {
executor.awaitTermination(10, TimeUnit.SECONDS);
executor.shutdownNow();
} catch (InterruptedException e) {
// TODO Log something
Thread.currentThread().interrupt();
}
}
}
The theory is: If future task doesn't exist, we create it, once it's there, if it's not done (because this is false legacy update 4/x where x ∈ [5,12] and the sleep is still in effect) then we completely skip and don't create a new executor.
The problem is that, from what I can tell, the executor.submit(task) does not in fact happen on a new tread. Like I said the legacy app is single threaded, and after I increased the sleep to 15s it was blindingly obvious that it was sending the whole current thread to sleep.
How would I put my taks on a completely new thread (using the concurrency library) and avoiding doing the task multiple times, even though the update method is being called way way too many times (and that is 100% out of my control). I think the future.isDone() thing works, but not 100%
if you are on Java 8 or higher, this is a better thing to do
CompletableFuture.runAsync(task);
because this will be executed on the Fork-join thread pool, that is managed by the JVM and you will not concern yourself by creating it nor shutting it down. and of course this will run asynchronously which match your requirements .
executor.submit() does start the task in a new thread, but right after executor.awaitTermination(10, TimeUnit.SECONDS); is waiting in the current thread for the task to be completed. There's no need to wait in the current thread, but there does need to be a way to determine if the task is already running.
The messy part is creating the ExecutorService each time - there's no need to recreate it each time. It can be an instance variable of the class and re-used. Ideally, it would be injected through a constructor so the class which created it can shut it down if that's really needed.
private final ExecutorService executor = Executors.newSingleThreadExecutor(); // or injected through constructor
private Future<?> futureTask;
#Override
public void update(Observable arg0, Object arg1) {
if (futureTask == null || futureTask.isDone()) {
futureTask = executor.submit(task);
}
}

How to interrupt a function call in Java

I am trying to use a Third Party Internal Library which is processing a given request. Unfortunately it is synchronous in nature. Also I have no control on the code for the same. Basically it is a function call. This function seems to a bit erratic in behavior. Sometimes this function takes 10 ms to complete processing and sometimes it takes up to 300 secs to process the request.
Can you suggest me a way to write a wrapper around this function so that it would throw an interrupted exception if the function does not complete processing with x ms/secs. I can live with not having the results and continue processing, but cannot tolerate a 3 min delay.
PS: This function internally sends an update to another system using JMS and waits for that system to respond and sends apart from some other calculations.
Can you suggest me a way to write a wrapper around this function so that it would throw an interrupted exception if the function does not complete processing with x ms/secs.
This is not possible. InterruptException only gets thrown by specific methods. You can certainly call thread.stop() but this is deprecated and not recommended for a number of reasons.
A better alternative would be for your code to wait for the response for a certain amount of time and just abandon the call if doesn't work. For example, you could submit a Callable to a thread pool that actually makes the call to the "Third Party Internal Library". Then your main code would do a future.get(...) with a specific timeout.
// allows 5 JMS calls concurrently, change as necessary or used newCachedThreadPool()
ExecutorService threadPool = Executors.newFixedThreadPool(5);
...
// submit the call to be made in the background by thread-pool
Future<Response> future = threadPool.submit(new Callable<Response>() {
public Response call() {
// this damn call can take 3 to 3000ms to complete dammit
return thirdPartyInternalLibrary.makeJmsRequest();
}
});
// wait for some max amount of time
Response response = null;
try {
response = future.get(TimeUnit.MILLISECONDS, 100);
} catch (TimeoutException te) {
// log that it timed out and continue or throw an exception
}
The problem with this method is that you might spawn a whole bunch of threads waiting for the library to respond to the remote JMS query that you would not have a lot of control over.
No easy solution.
This will throw a TimeoutException if the lambda doesn't finish in the time allotted:
CompletableFuture.supplyAsync(() -> yourCall()).get(1, TimeUnit.SECONDS)
Being that this is 3rd party you cannot modify the code. As such you will need to do two things
Launch the execution in a new thread.
Wait for execution in current thread, with timeout.
One possible way would be to use a Semaphore.
final Semaphore semaphore = new Semaphore(0);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
// do work
semaphore.release();
}
});
t.start();
try {
semaphore.tryAcquire(1, TimeUnit.SECONDS); // Whatever your timeout is
} catch (InterruptedException e) {
// handle cleanup
}
The above method is gross, I would suggest instead updateing your desing to use a dedicated worker queue or RxJava with a timeout if possible.

InterruptedException inside ExecutorService

Should we set the interrupted flag when catching an InterruptedException inside a task managed by an ExecutorService? Or should we just swallow the InterruptedException?
Example:
final ExecutorService service = ...;
final Object object = ...;
service.submit(() -> {
try {
while (!condition) {
object.wait();
}
} catch (final InterruptedException exception) {
Thread.currentThread().interrupt(); // yes or no?
}
});
In a task submitted to an ExecutorService, receiving an interrupt is a signal to cancel execution of the task. So, in your code example, the answer is "no", don't set the interrupt again.
Re-asserting the interrupt status, as far as I can see in the source code, will be ignored, but it does waste a bit of work in the executor as an InterruptedException is raised immediately if the worker thread tries to get another task, which is then determined to be spurious and cleared based on the state of the executor.
Shutting down the executor in a timely manner depends on tasks exiting in response to an interrupt; it does not depend on tasks restoring the interrupt status.
As this good article suggest, don't ever swallow InterruptedException.

Java - stopping all tasks in ExecutorService

I have a few executor services which schedule local tasks such as reading a file, connecting to db etc. These processes do huge amount of logging, which is extensive based on the fact there are many threads running concurrently, writing their own thing into the log.
Now, at some point in time an exception can be raised, which reaches the main method where all exceptions are caught. I am then shutting down all the services and cancelling each task, hoping to prevent all further messages to the log. Unfortunately, the messages are still showing up after I shut everything down... Any ideas?
UPDATE:
Here is some code
public class Scheduler{
private final ExecutorService service;
private final ConcurrentMap<Object, Future<V>> cache;
...
public void shutDown() {
service.shutdownNow();
for (Future task : cache.values())
task.cancel(true);
}
The task will carry on running until it reaches a point where it detects the Thread has been interrupted. This can happen when calling some System or Thread functions and you may get an exception thrown. In your case you probably need to check yourself by calling
Thread.currentThread().isInterrupted()
It is a good idea to do this if your code runs loops and you are expecting to be stopped in this way.
When you shutdownNow your executor or call cancel(true) (by the way shutdownNow already cancels the already submitted tasks so your loop is unnecessary) your tasks get interrupted.
Depending on how they react to the interruption, they might then:
stop what they are doing immediately
stop what they are doing after a while, because the interruption signal is not being checked regularly enough
continue doing what they are doing because the interruption signal has been ignored
For example, if your tasks run a while(true) loop, you can replace it with something like:
while(!Thread.currentThread().isInterrupted()) {
//your code here
}
cleanup();
//and exit
Another example:
for (int i = 0; i < aBigNumber; i++) {
if (Thread.currentThread().isInterrupted()) { break; }
//rest of the code for the loop
}
cleanup();
//and exit
Another example, if you call a method that throws InterruptedException:
try {
Thread.sleep(forever); //or some blocking IO or file reading...
} catch (InterruptedException e) {
cleanup();
Thread.currentThread.interrupt();
//and exit
}
Executors support 2 approaches of shutdown
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.
There are no guarantees beyond best-effort attempts to stop processing actively executing tasks.
Ref : http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ExecutorService.html#shutdownNow()
- Try using the shutdowNow() method, it will shutdown all the task started by this Executor throwing InterruptedException, but IO and Synchronized operation can't be interrupted.
Eg:
ExecutorService executor = Executors.newFixedThreadPool();
executor.execute();
...
...
executor.shutdownNow();
- cancel(true) method can be used with submit() method to shutdown a particular task.

Wait for task to finish before terminating in ScheduledThreadPoolExecutor

I have a Runnable implementation that does some work which might take some time and I am trying to schedule it using ScheduledThreadPoolExecutorwith scheduleAtFixedRate method. Now I want to ensure that shut down is graceful that means, Before terminating, task should be allowed to run completely. I have written following code for shutdown.
public void shutDown() throws Exception {
try {
LOG.info("Gracefully shutting down executor");
executor.shutdown();
if (!executor.awaitTermination(SHUTDOWN_TIMEOUT, TimeUnit.SECONDS)) {
// cancels currently executing tasks.
LOG.info("Executor is still alive. Forcing executor thread pool to shut down");
executor.shutdownNow();
// Wait a while for tasks to respond to being cancelled
if (!executor.awaitTermination(SHUTDOWN_TIMEOUT, TimeUnit.SECONDS)) {
LOG.fatal("Executor thread pool did not terminate");
throw new Exception("Unable to shut down executor thread pool forcefully");
}
LOG.info("Executor shut down.");
}
} catch (Exception e) {
LOG.error("Exception shutting down executor", e);
throw e;
}
}
But problem with this is, I have to specify time to wait explicitly and I can not predict time taken by task in advance. Is there a way to make executor wait indefinitely until executing task finishes without having to mention time to wait? Or is there a better way to work on above scenario?
Thanks
Jitendra
Simplest solution is to "overprovision" so to speak. I suggest you use a huge timeout period that in no way can be exceeded by the time needed for a single task to execute, like:
// do you have tasks that can take more than 2^63 - 1 days to finish? :)
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
Use shutdown() to begin a graceful termination, and then use awaitTermination(long, TimeUnit) to wait for the executor service to finish shutting down.
As it was noted in the comment executor.shutdown() is not forcing any tasks to exit but rather it prevents new ones from being accepted. Have a look in the javadoc.
Another advice is if you want to get hold of your tasks as soon as they complete, you can implement Callable<T> instead of a Runnable that it's of a generic type and returns a value of type T. Then you can wrap this Callable<T> into a FutureTask<V> and submit that to your ScheduledThreadPoolExecutor. You can then loop through your tasks as soon as they have completed their work and are available. So in short something like this (notice as soon as we are done loading the scheduler with tasks it's safe to shut it down meaning that we don't allow any further tasks to be submitted from then on):
ScheduledExecutorService schedulerExecutor = Executors.newScheduledThreadPool(n);
Callable<Integer> myTask = . . .;
FutureTask<Integer> task = new FutureTask<Integer>(myTask);
schedulerExecutor.scheduleAtFixedRate(task, 0, 1, TimeUnit.SECONDS);
schedulerExecutor.shutdown();

Categories

Resources