How to handle uncaught exceptions from CompletableFuture.runAsync - java

Our application has some code that runs asynchronously that is failing. Like this:
CompletableFuture.runAsync(
() -> { throw new RuntimeException("bad"); },
executorService
);
We want default exception handling code that can catch these errors, in case specific uses forget to handle exceptions (this came from a production bug).
This is apparently tricky. The answer given in Handling exceptions from Java ExecutorService tasks does not work.
It relies on the task being a Future<?> and then calling get() on it, resulting in the exception being thrown again. But this is not the case for runAsync code.
runAsync creates a java.util.concurrent.CompletableFuture.AsyncRun class that seems to try to supress all exceptions. Despite being a Future itself, it does not indicate being isDone(), and seems to provide no way to get exceptions out of it.
So, given the following boilerplate, how should we catch these gnarly exceptions?
Note that we really want something that will catch all unhandled exceptions in runAsync code, not something we can add to each runAsync invocation. It's just too easy to forget to add handling code to each one.
public class ExceptionTest {
public static void main(String[] args) throws RuntimeException {
ExecutorService executorService = new ThreadPoolExecutor(
1, 1, 0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()
) {
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
// TODO: Magically extract the exception from `r`
}
};
CompletableFuture.runAsync(
() -> { throw new RuntimeException("bad"); },
executorService
);
}
}

So, this is a terrible hack, but it does handle the case where you forget to call exceptionally when using runAsync. I'd love to see more generic and less hacky solutions.
It works by intercepting the AsyncRun before it's executed and patching on an exceptionally block.
Seriously janky, though. But it'll work, maybe, until Oracle changes how runAsync works.
ExecutorService executorService = new ThreadPoolExecutor(
1,
1,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()
) {
#Override
protected void beforeExecute(final Thread t, final Runnable r) {
super.beforeExecute(t, r);
if (r.getClass().getName().equals("java.util.concurrent.CompletableFuture$AsyncRun")) {
try {
final Field f = r.getClass().getDeclaredField("dep");
f.setAccessible(true);
((CompletableFuture<?>) f.get(r)).exceptionally(e -> {
LoggerFactory.getLogger(ExceptionTest.class).error("Error in runAsync " + r, e);
UnsafeUtils.getUnsafe().throwException(e);
return null;
});
} catch (Exception e) {
System.out.println("Failed to hack CompletableFuture$AsyncRun to report exceptions.");
}
}
}
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if (t == null && r instanceof Future<?>) {
try {
Future<?> future = (Future<?>) r;
if (future.isDone()) {
future.get();
}
} catch (CancellationException ce) {
t = ce;
} catch (ExecutionException ee) {
t = ee.getCause();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
if (t != null) {
LoggerFactory.getLogger(ExceptionTest.class).error("Error in async task " + r, t);
}
}
};

Related

tomcat jdbc - ScheduledExecutre inserts work initially then fail, without error [duplicate]

I use ScheduledExecutorService to execute a method periodically.
p-code:
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture<?> handle =
scheduler.scheduleWithFixedDelay(new Runnable() {
public void run() {
//Do business logic, may Exception occurs
}
}, 1, 10, TimeUnit.SECONDS);
My question:
How to continue the scheduler, if run() throws Exception?
Should I try-catch all Exception in method run()? Or any built-in callback method to handle the Exception? Thanks!
tl;dr
Any exception escaping your run method halts all further work, without notice.
Always use a try-catch within your run method. Try to recover if you want scheduled activity to continue.
#Override
public void run ()
{
try {
doChore();
} catch ( Exception e ) {
logger.error( "Caught exception in ScheduledExecutorService. StackTrace:\n" + t.getStackTrace() );
}
}
The Problem
The question refers to the critical trick with a ScheduledExecutorService: Any thrown exception or error reaching the executor causes the executor to halt. No more invocations on the Runnable, no more work done. This work stoppage happens silently, you'll not be informed. This naughty-language blog posting entertainingly narrates the hard way to learn about this behavior.
The Solution
The answer by yegor256 and the answer by arun_suresh both seem to be basically correct. Two issues with those answers:
Catch errors as well as exceptions
A bit complicated
Errors and Exceptions ?
In Java we normally catch only exceptions, not errors. But in this special case of ScheduledExecutorService, failing to catch either will mean a work stoppage. So you may want to catch both. I'm not 100% sure about this, not knowing fully the implications of catching all errors. Please correct me if needed.
One reason to catch errors as well as exceptions might involve the use of libraries within your task. See the comment by jannis.
One way to catch both exceptions and errors is to catch their superclass, Throwable for an example.
} catch ( Throwable t ) {
…rather than…
} catch ( Exception e ) {
Simplest Approach: Just Add a Try-Catch
But both answers are a bit complicated. Just for the record, I'll show the simplest solution:
Always wrap your Runnable's code in a Try-Catch to catch any and all exceptions and errors.
Lambda Syntax
With a lambda (in Java 8 and later).
final Runnable someChoreRunnable = () -> {
try {
doChore();
} catch ( Throwable t ) { // Catch Throwable rather than Exception (a subclass).
logger.error( "Caught exception in ScheduledExecutorService. StackTrace:\n" + t.getStackTrace() );
}
};
Old-Fashioned Syntax
The old-fashioned way, before lambdas.
final Runnable someChoreRunnable = new Runnable()
{
#Override
public void run ()
{
try {
doChore();
} catch ( Throwable t ) { // Catch Throwable rather than Exception (a subclass).
logger.error( "Caught exception in ScheduledExecutorService. StackTrace:\n" + t.getStackTrace() );
}
}
};
In Every Runnable/Callable
Regardless of a ScheduledExecutorService, it seems sensible to me to always use a general try-catch( Exception† e ) in any run method of a Runnable. Ditto for any call method of a Callable.
Complete example code
In real work, I would likely define the Runnable separately rather than nested. But this makes for neat all-in-one example.
package com.basilbourque.example;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* Demo `ScheduledExecutorService`
*/
public class App {
public static void main ( String[] args ) {
App app = new App();
app.doIt();
}
private void doIt () {
// Demonstrate a working scheduled executor service.
// Run, and watch the console for 20 seconds.
System.out.println( "BASIL - Start." );
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture < ? > handle =
scheduler.scheduleWithFixedDelay( new Runnable() {
public void run () {
try {
// doChore ; // Do business logic.
System.out.println( "Now: " + ZonedDateTime.now( ZoneId.systemDefault() ) ); // Report current moment.
} catch ( Exception e ) {
// … handle exception/error. Trap any unexpected exception here rather to stop it reaching and shutting-down the scheduled executor service.
// logger.error( "Caught exception in ScheduledExecutorService. StackTrace:\n" + e.getStackTrace() );
} // End of try-catch.
} // End of `run` method.
} , 0 , 2 , TimeUnit.SECONDS );
// Wait a long moment, for background thread to do some work.
try {
Thread.sleep( TimeUnit.SECONDS.toMillis( 20 ) );
} catch ( InterruptedException e ) {
e.printStackTrace();
}
// Time is up. Kill the executor service and its thread pool.
scheduler.shutdown();
System.out.println( "BASIL - Done." );
}
}
When run.
BASIL - Start.
Now: 2018-04-10T16:46:01.423286-07:00[America/Los_Angeles]
Now: 2018-04-10T16:46:03.449178-07:00[America/Los_Angeles]
Now: 2018-04-10T16:46:05.450107-07:00[America/Los_Angeles]
Now: 2018-04-10T16:46:07.450586-07:00[America/Los_Angeles]
Now: 2018-04-10T16:46:09.456076-07:00[America/Los_Angeles]
Now: 2018-04-10T16:46:11.456872-07:00[America/Los_Angeles]
Now: 2018-04-10T16:46:13.461944-07:00[America/Los_Angeles]
Now: 2018-04-10T16:46:15.463837-07:00[America/Los_Angeles]
Now: 2018-04-10T16:46:17.469218-07:00[America/Los_Angeles]
Now: 2018-04-10T16:46:19.473935-07:00[America/Los_Angeles]
BASIL - Done.
Another example
Here is another example. Here our task is meant to run about twenty times, once every five seconds for a minute. But on the fifth run, we throw an exception.
public class App2
{
public static void main ( String[] args )
{
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
final AtomicInteger counter = new AtomicInteger( 0 );
Runnable task = ( ) -> {
int c = counter.incrementAndGet();
if ( c > 4 )
{
System.out.println( "THROWING EXCEPTION at " + Instant.now() );
throw new IllegalStateException( "Bogus exception. c = " + c + ". " + Instant.now() ); // Notice how this exception is silently swallowed by the scheduled executor service, while causing a work stoppage.
}
System.out.println( "Task running. c = " + c + ". " + Instant.now() );
};
ses.scheduleAtFixedRate( task , 0 , 5 , TimeUnit.SECONDS );
try { Thread.sleep( Duration.ofMinutes( 1 ).toMillis() ); }catch ( InterruptedException e ) { e.printStackTrace(); }
System.out.println( "Main thread done sleeping. " + Instant.now() );
ses.shutdown();
try { ses.awaitTermination( 1 , TimeUnit.MINUTES ); }catch ( InterruptedException e ) { e.printStackTrace(); }
}
}
When run.
Task running. c = 1. 2021-10-14T20:09:16.317995Z
Task running. c = 2. 2021-10-14T20:09:21.321536Z
Task running. c = 3. 2021-10-14T20:09:26.318642Z
Task running. c = 4. 2021-10-14T20:09:31.318320Z
THROWING EXCEPTION at 2021-10-14T20:09:36.321458Z
Main thread done sleeping. 2021-10-14T20:10:16.320430Z
Notice:
The exception is silently swallowed by the scheduled executor service.
A work stoppage occurs. No further executions of our task are scheduled. Again, a silent problem.
So when your task throws an exception, you get the worst outcome possible: Silent work stoppage with no explanation.
The solution, as mentioned above: Always use a try-catch within your run method.
† Or perhaps Throwable instead of Exception to catch Error objects too.
You should use the ScheduledFuture object returned by your scheduler.scheduleWithFixedDelay(...) like so :
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture<?> handle =
scheduler.scheduleWithFixedDelay(new Runnable() {
public void run() {
throw new RuntimeException("foo");
}
}, 1, 10, TimeUnit.SECONDS);
// Create and Start an exception handler thread
// pass the "handle" object to the thread
// Inside the handler thread do :
....
try {
handle.get();
} catch (ExecutionException e) {
Exception rootException = e.getCause();
}
Old question but the accepted answer doesn't give explanations and provides a poor example and the most upvoted answer is right on some points but finally encourages you to add catch exceptions in every Runnable.run() method.
I disagree because :
it is not neat : not standard for a task to catch its own exceptions.
it is not robust : a new Runnable subclass could forget to perform the exception catch and the failover associated.
it defeats the low coupling promoted by tasks since that couples the tasks to execute with the way of handling the task result.
it mixes responsibilities : that is not the task responsibility to handle the exception or to communicate the exception to the caller. A task is something to execute.
I think that the exception propagation should be performed by the ExecutorService framework and actually it offers that feature.
Besides, trying to be too clever by trying to short-circuiting the ExecutorService way of working is not a good idea either : the framework may evolve and you want to use it in a standard way.
At last, letting the ExecutorService framework to make its job doesn't mean necessarily halting the subsequent invocations task.
If a scheduled task encounters an issue, that is the caller responsibility to re-schedule or not the task according to the issue cause.
Each layer has its its responsibilities. Keeping these make code both clear and maintainable.
ScheduledFuture.get() : the right API to catch exceptions and errors occurred in the task
ScheduledExecutorService.scheduleWithFixedDelay()/scheduleAtFixRate() state in their specification :
If any execution of the task encounters an exception, subsequent
executions are suppressed. Otherwise, the task will only terminate via
cancellation or termination of the executor.
It means that ScheduledFuture.get() doesn't return at each scheduled invocation but that it returns for the last invocation of the task, that is a task cancelation : caused by ScheduledFuture.cancel() or a exception thrown in the task.
So handling the ScheduledFuture return to capture the exception with ScheduledFuture.get() looks right :
try {
future.get();
} catch (InterruptedException e) {
// ... to handle
} catch (ExecutionException e) {
// ... and unwrap the exception OR the error that caused the issue
Throwable cause = e.getCause();
}
Example with the default behavior : halting the scheduling if one of the task execution encounters an issue
It executes a task that for the third executions thrown an exception and terminates the scheduling.
In some scenarios, we want that.
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class ScheduledExecutorServiceWithException {
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
// variable used to thrown an error at the 3rd task invocation
AtomicInteger countBeforeError = new AtomicInteger(3);
// boolean allowing to leave the client to halt the scheduling task or not after a failure
Future<?> futureA = executor
.scheduleWithFixedDelay(new MyRunnable(countBeforeError), 1, 2, TimeUnit.SECONDS);
try {
System.out.println("before get()");
futureA.get(); // will return only if canceled
System.out.println("after get()");
} catch (InterruptedException e) {
// handle that : halt or no
} catch (ExecutionException e) {
System.out.println("exception caught :" + e.getCause());
}
// shutdown the executorservice
executor.shutdown();
}
private static class MyRunnable implements Runnable {
private final AtomicInteger invocationDone;
public MyRunnable(AtomicInteger invocationDone) {
this.invocationDone = invocationDone;
}
#Override
public void run() {
System.out.println(Thread.currentThread().getName() + ", execution");
if (invocationDone.decrementAndGet() == 0) {
throw new IllegalArgumentException("ohhh an Exception in MyRunnable");
}
}
}
}
Output :
before get()
pool-1-thread-1, execution
pool-1-thread-1, execution
pool-1-thread-1, execution
exception caught :java.lang.IllegalArgumentException: ohhh an Exception in MyRunnable
Example with the possibility to go on the scheduling if one of the task execution encounters an issue
It executes a task that throws an exception at the two first executions and throws an error at the third one.
We can see that the client of the tasks can choose to halt or not the scheduling : here I go on in cases of exception and I stop in case of error.
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class ScheduledExecutorServiceWithException {
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
// variable used to thrown an error at the 3rd task invocation
AtomicInteger countBeforeError = new AtomicInteger(3);
// boolean allowing to leave the client to halt the scheduling task or not after a failure
boolean mustHalt = true;
do {
Future<?> futureA = executor
.scheduleWithFixedDelay(new MyRunnable(countBeforeError), 1, 2, TimeUnit.SECONDS);
try {
futureA.get(); // will return only if canceled
} catch (InterruptedException e) {
// handle that : halt or not halt
} catch (ExecutionException e) {
if (e.getCause() instanceof Error) {
System.out.println("I halt in case of Error");
mustHalt = true;
} else {
System.out.println("I reschedule in case of Exception");
mustHalt = false;
}
}
}
while (!mustHalt);
// shutdown the executorservice
executor.shutdown();
}
private static class MyRunnable implements Runnable {
private final AtomicInteger invocationDone;
public MyRunnable(AtomicInteger invocationDone) {
this.invocationDone = invocationDone;
}
#Override
public void run() {
System.out.println(Thread.currentThread().getName() + ", execution");
if (invocationDone.decrementAndGet() == 0) {
throw new Error("ohhh an Error in MyRunnable");
} else {
throw new IllegalArgumentException("ohhh an Exception in MyRunnable");
}
}
}
}
Output :
pool-1-thread-1, execution
I reschedule in case of Exception
pool-1-thread-1, execution
I reschedule in case of Exception
pool-1-thread-2, execution
I halt in case of Error
I know that this is old question, but if somebody is using delayed CompletableFuture with ScheduledExecutorService then should handle this in that way:
private static CompletableFuture<String> delayed(Duration delay) {
CompletableFuture<String> delayed = new CompletableFuture<>();
executor.schedule(() -> {
String value = null;
try {
value = mayThrowExceptionOrValue();
} catch (Throwable ex) {
delayed.completeExceptionally(ex);
}
if (!delayed.isCompletedExceptionally()) {
delayed.complete(value);
}
}, delay.toMillis(), TimeUnit.MILLISECONDS);
return delayed;
}
and handling exception in CompletableFuture:
CompletableFuture<String> delayed = delayed(Duration.ofSeconds(5));
delayed.exceptionally(ex -> {
//handle exception
return null;
}).thenAccept(value -> {
//handle value
});
Another solution would be to swallow an exception in the Runnable. You can use a convenient VerboseRunnable class from jcabi-log, for example:
import com.jcabi.log.VerboseRunnable;
scheduler.scheduleWithFixedDelay(
new VerboseRunnable(
Runnable() {
public void run() {
// do business logic, may Exception occurs
}
},
true // it means that all exceptions will be swallowed and logged
),
1, 10, TimeUnit.SECONDS
);
Inspired by #MBec solution, I wrote a nice generic wrapper for the ScheduledExecutorService that:
will catch and print any unhandled thrown exception.
will return a Java 8 CompletableFuture instead of a Future.
:)
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* This class use as a wrapper for the Native Java ScheduledExecutorService class.
* It was created in order to address the very unpleasant scenario of silent death!
* explanation: each time an unhandled exception get thrown from a running task that runs by ScheduledExecutorService
* the thread will die and the exception will die with it (nothing will propagate back to the main thread).
*
* However, HonestScheduledExecutorService will gracefully print the thrown exception with a custom/default message,
* and will also return a Java 8 compliant CompletableFuture for your convenience :)
*/
#Slf4j
public class HonestScheduledExecutorService {
private final ScheduledExecutorService scheduledExecutorService;
private static final String DEFAULT_FAILURE_MSG = "Failure occurred when running scheduled task.";
HonestScheduledExecutorService(ScheduledExecutorService scheduledExecutorService) {
this.scheduledExecutorService = scheduledExecutorService;
}
public CompletableFuture<Object> scheduleWithFixedDelay(Callable callable, String onFailureMsg, long initialDelay, long delay, TimeUnit unit) {
final String msg = StringUtils.isEmpty(onFailureMsg) ? DEFAULT_FAILURE_MSG : onFailureMsg;
CompletableFuture<Object> delayed = new CompletableFuture<>();
scheduledExecutorService.scheduleWithFixedDelay(() -> {
try {
Object result = callable.call();
delayed.complete(result);
} catch (Throwable th) {
log.error(msg, th);
delayed.completeExceptionally(th);
}
}, initialDelay, delay, unit);
return delayed;
}
public CompletableFuture<Void> scheduleWithFixedDelay(Runnable runnable, String onFailureMsg, long initialDelay, long delay, TimeUnit unit) {
final String msg = StringUtils.isEmpty(onFailureMsg) ? DEFAULT_FAILURE_MSG : onFailureMsg;
CompletableFuture<Void> delayed = new CompletableFuture<>();
scheduledExecutorService.scheduleWithFixedDelay(() -> {
try {
runnable.run();
delayed.complete(null);
} catch (Throwable th) {
log.error(msg, th);
delayed.completeExceptionally(th);
}
}, initialDelay, delay, unit);
return delayed;
}
public CompletableFuture<Object> schedule(Callable callable, String failureMsg, long delay, TimeUnit unit) {
final String msg = StringUtils.isEmpty(failureMsg) ? DEFAULT_FAILURE_MSG : failureMsg;
CompletableFuture<Object> delayed = new CompletableFuture<>();
scheduledExecutorService.schedule(() -> {
try {
Object result = callable.call();
delayed.complete(result);
} catch (Throwable th) {
log.error(msg, th);
delayed.completeExceptionally(th);
}
}, delay, unit);
return delayed;
}
public CompletableFuture<Void> schedule(Runnable runnable, String failureMsg, long delay, TimeUnit unit) {
final String msg = StringUtils.isEmpty(failureMsg) ? DEFAULT_FAILURE_MSG : failureMsg;
CompletableFuture<Void> delayed = new CompletableFuture<>();
scheduledExecutorService.schedule(() -> {
try {
runnable.run();
delayed.complete(null);
} catch (Throwable th) {
log.error(msg, th);
delayed.completeExceptionally(th);
}
}, delay, unit);
return delayed;
}
public CompletableFuture<Object> scheduleAtFixedRate(Callable callable, String failureMsg, long initialDelay, long period, TimeUnit unit) {
final String msg = StringUtils.isEmpty(failureMsg) ? DEFAULT_FAILURE_MSG : failureMsg;
CompletableFuture<Object> delayed = new CompletableFuture<>();
scheduledExecutorService.scheduleAtFixedRate(() -> {
try {
Object result = callable.call();
delayed.complete(result);
} catch (Throwable th) {
log.error(msg, th);
delayed.completeExceptionally(th);
}
}, initialDelay, period, unit);
return delayed;
}
public CompletableFuture<Void> scheduleAtFixedRate(Runnable runnable, String failureMsg, long initialDelay, long period, TimeUnit unit) {
final String msg = StringUtils.isEmpty(failureMsg) ? DEFAULT_FAILURE_MSG : failureMsg;
CompletableFuture<Void> delayed = new CompletableFuture<>();
scheduledExecutorService.scheduleAtFixedRate(() -> {
try {
runnable.run();
delayed.complete(null);
} catch (Throwable th) {
log.error(msg, th);
delayed.completeExceptionally(th);
}
}, initialDelay, period, unit);
return delayed;
}
public CompletableFuture<Object> execute(Callable callable, String failureMsg) {
final String msg = StringUtils.isEmpty(failureMsg) ? DEFAULT_FAILURE_MSG : failureMsg;
CompletableFuture<Object> delayed = new CompletableFuture<>();
scheduledExecutorService.execute(() -> {
try {
Object result = callable.call();
delayed.complete(result);
} catch (Throwable th) {
log.error(msg, th);
delayed.completeExceptionally(th);
}
});
return delayed;
}
public CompletableFuture<Void> execute(Runnable runnable, String failureMsg) {
final String msg = StringUtils.isEmpty(failureMsg) ? DEFAULT_FAILURE_MSG : failureMsg;
CompletableFuture<Void> delayed = new CompletableFuture<>();
scheduledExecutorService.execute(() -> {
try {
runnable.run();
delayed.complete(null);
} catch (Throwable th) {
log.error(msg, th);
delayed.completeExceptionally(th);
}
});
return delayed;
}
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
return scheduledExecutorService.awaitTermination(timeout, unit);
}
public List<Runnable> shutdownNow() {
return scheduledExecutorService.shutdownNow();
}
public void shutdown() {
scheduledExecutorService.shutdown();
}
}
An elegent way to catch the exception and keep scheduled tasks alive.
First, define a functional interface.
#FunctionalInterface
interface NoSuppressedRunnable extends Runnable {
#Override
default void run() {
try {
doRun();
} catch (Exception e) {
log.error("...", e);
}
}
void doRun();
}
Then, commit the job like this.
executorService.scheduleAtFixedRate((NoSuppressedRunnable) () -> {
// Complier implies that this is an implement of doRun() once you put the cast above
}, 0, 60L, TimeUnit.SECONDS);
Any exception in the run() of a thread which is passed to (ScheduledExecutorService) is never thrown out and if we use future.get() to get status, then the main thread waits infinitely
Personally, I disagree with all the answers here. The main issue with all of them is they provide the same solution in weird flavors. Instead, what you should be doing is creating your own thread factory that installs an uncaught exception handler on the thread that is being created. For example, this is the DefaultThreadFactory that is installed into any executor that would create threads on its own. Shamefully, it's still a private class as of Java 11, since I would like to extend it instead of copying it into my codebase. Below is a snippet how it appears in Executors.java file.
private static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
As you can see, the interface itself is a single method that handles creating new threads. There isn't much magic to it besides figuring out the thread group where is the thread factory created in. The interesting bit is that threads are created as non-daemon.
When the thread is created, you can call setThreadUncaughtExceptionHandler which accepts a handler where you should be handling any uncaught exceptions that had happened in that thread. By default, it will be inherited from your thread group, which has the following
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
parent.uncaughtException(t, e);
} else {
Thread.UncaughtExceptionHandler ueh =
Thread.getDefaultUncaughtExceptionHandler();
if (ueh != null) {
ueh.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
System.err.print("Exception in thread \""
+ t.getName() + "\" ");
e.printStackTrace(System.err);
}
}
}
By default, it will attempt to delegate handling to parent thread group if it exists, and only then test for platform default uncaught exception handler. Usually it is not explicitly installed. If you want to do some real damage to poor codebases that are not aware of this, you can install one via Thread#setDefaultUncaughtExceptionHandler. Don't worry, you won't get to do that if the runtime has Security manager in place.
If you were to install your own handler, that handler will be called instead of the group one.
Now with that out of the way, to your question: How do you handle exceptions in Executors. By default, a thread is considered dead if code is unable to handle its own errors. And I think you should adhere to that. Uncaught exception handler won't save your thread. Instead it will help you diagnose what happened. To segway into ScheduledExecutor implementations, which permit periodic execution of a runnable, the same rules apply: if one execution fails, the thread is killed, along with the runnable that was supposed to get run.
In short, handle your own errors. We have checked exceptions for a reason.
But what about unchecked exceptions?
Funny, since I will commit the same sin as other posters do: use try/catch on Throwable, but assert that it's not a ThreadDeath error. If you do get one, you must rethrow it to ensure the thread actually does die.

Catching uncaught exceptions from CompletableFuture

I'm trying to catch uncaught exceptions on futures like this CompletableFuture.runAsync(() -> {throw new RuntimeException();});
My goal is to make these exceptions not silent when developpers forget to handle them.
Calling get() or join() and try/catch exceptions is not an option because it is not global to all usages of future in the code base
Adding .exceptionnaly(...) or handle(...) is not an option for the same reason. It's exactly what I'm trying to prevent
Here's what I do (which doesn't work)
public class Main {
public static void main(String[] args) throws InterruptedException, ExecutionException {
System.setProperty("java.util.concurrent.ForkJoinPool.common.exceptionHandler", UncaughtExceptionHandler.class.getName());
CompletableFuture.runAsync(() -> {
System.out.println("async");
throw new RuntimeException();
});
System.out.println("Done");
Thread.sleep(1000);
}
static class UncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
#Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("Uncaught!");
}
}
}
It prints
Done
Async
What am I missing ?
EDIT
I tried this but still not working
public class Main {
public static void main(String[] args) throws InterruptedException {
CompletableFuture.runAsync(() -> {
System.out.println("Async");
throw new RuntimeException();
},
new ForkJoinPool(
Runtime.getRuntime().availableProcessors(),
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
(t, e) -> System.out.println("Uncaught!"), // UncaughtExceptionHandler
false));
System.out.println("Done");
Thread.sleep(1000);
}
}
It seems that the ForkJoinPool ignores its UncaughtExceptionHandler, and even its ForkJoinWorkerThreadFactory because I tried to define that as well
Version 1: everything works as it should, no exception thrown by the RunAsync method ... no exception handling occurs...
public static void main(String[] args) throws InterruptedException {
UncaughtExceptionHandler uncaughtExceptionHandler = new UncaughtExceptionHandler();
System.setProperty("java.util.concurrent.ForkJoinPool.common.exceptionHandler", UncaughtExceptionHandler.class.getName());
CompletableFuture.runAsync(() -> {
System.out.println("async");
}).exceptionally((ex) -> {
uncaughtExceptionHandler.uncaughtException(Thread.currentThread(), ex);
return null;
});
System.out.println("Done");
Thread.sleep(1000);
}
static class UncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
public UncaughtExceptionHandler() { }
public void uncaughtException(Thread t, Throwable e) {
System.out.println("Uncaught!");
}
}
Output:
async
Done
Process finished with exit code 0
Version 2: Exception thrown by runAsync() and the exception handler does its thing.
public static void main(String[] args) throws InterruptedException {
UncaughtExceptionHandler uncaughtExceptionHandler = new UncaughtExceptionHandler();
System.setProperty("java.util.concurrent.ForkJoinPool.common.exceptionHandler", UncaughtExceptionHandler.class.getName());
CompletableFuture.runAsync(() -> {
throw new RuntimeException("Something went Wrong");
}).exceptionally((ex) -> {
uncaughtExceptionHandler.uncaughtException(Thread.currentThread(), ex);
return null;
});
System.out.println("Done");
Thread.sleep(1000);
}
static class UncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
public UncaughtExceptionHandler() { }
public void uncaughtException(Thread t, Throwable e) {
System.out.println("Uncaught!");
}
}
Output:
Uncaught!
Done
Process finished with exit code 0
The two ways to handle exceptions:
.exceptionally(ex -> { your_code }) - gives you a chance to recover from errors generated from the original Future. You can log the exception here and return a default value.
.handle((result, ex) -> { your_code }) - called whether or not an exception occurs. Can also be used to handle exceptions
You are missing the fact that a CompletableFuture executes its task in the background (using an Executor) and handles any exception thrown by its task, in order to report the task’s status from methods like isCompletedExceptionally, so there is no uncaught exception.
The exception can be propagated by calling the CompletableFuture’s get() method:
CompletableFuture<?> future =
CompletableFuture.runAsync(() -> {
System.out.println("async");
throw new RuntimeException();
});
future.get();
System.out.println("Done");
Update:
Since you don’t want to wait for the exception, you can use exceptionally or exceptionallyAsync to respond to any exception thrown by the task:
CompletableFuture<?> future =
CompletableFuture.runAsync(() -> {
System.out.println("async");
throw new RuntimeException();
});
future.exceptionally(e -> {
System.out.println("Uncaught!");
return null;
});
System.out.println("Done");

Use CompletableFuture to execute single or multiple Callables and avoid blocking

I execute a few callables through ThreadPoolExecutor. If thread list contains only 1 callable then I directly call call method of my CallableService. If list contains more than 1 callables then I execute all those threads in parallel via thread pool executor.
How can I achieve this with Java 8 CompletableFuture? And if future.get() is enhanced to avoid blocking, that will be a plus.
private static ThreadPoolExecutor myThreadPoolExecutor = new ThreadPoolExecutor(0, 100, 5L, TimeUnit.SECONDS, new SynchronousQueue<>());
public static void execute(List<Callable<Boolean>> threadList) throws Exception {
List<Future<Boolean>> futureList = null;
CallableService singleService = (CallableService) threadList.get(0);
if (1 == threadList.size()) {
singleService.call();
}
else {
try {
futureList = myThreadPoolExecutor.invokeAll(threadList);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
if (null != futureList) {
for (Future<Boolean> future : futureList) {
try {
future.get();
}
catch (Exception e) {
//do some calculations here and then throw exception
throw new Exception(e.getMessage(), e);
}
}
}
}
There is no need for CompletableFuture, as the way you use the ExecutorService is sufficient, though, there are some aspects of the code flow which could be improved. You fetch the first element, even when not needed, and you cast it to CallableService for no reason, as you can call the method via the Callable interface already. In the other branch you are catching InterruptedException and proceeding, so the caller would never know that not all jobs have been executed. And in a straight-forward code flow, you don't need to check the list for null:
public static void execute(List<Callable<Boolean>> threadList) throws Exception {
if(1 == threadList.size()) {
Callable<Boolean> singleService = threadList.get(0);
singleService.call();
}
else {
List<Future<Boolean>> futureList = myThreadPoolExecutor.invokeAll(threadList);
for(Future<Boolean> future : futureList) {
try {
future.get();
}
catch(Exception e) {
//do some calculations here and then throw exception
throw new Exception(e.getMessage(), e);
}
}
}
}
You could shorten it further to
public static void execute(List<Callable<Boolean>> threadList) throws Exception {
if(1 == threadList.size()) {
threadList.get(0).call();
}
else {
for(Future<Boolean> future : myThreadPoolExecutor.invokeAll(threadList)) {
try {
future.get();
}
catch(Exception e) {
//do some calculations here and then throw exception
throw new Exception(e.getMessage(), e);
}
}
}
}
But that's a matter of preferred coding style. But note that it caught my eye that in the single element case, you're not performing the same exception handling.
To use CompletableFuture, we need an adapter method, as the convenience method supplyAsync requires a Supplier instead of a Callable. Using a modified variant of this answer, we get
public static void execute(List<Callable<Boolean>> threadList) throws Exception {
if(1 == threadList.size()) {
threadList.get(0).call();
}
else {
CompletableFuture<?> all = CompletableFuture.allOf(
threadList.stream()
.map(c -> callAsync(c, myThreadPoolExecutor))
.toArray(CompletableFuture<?>[]::new));
try {
all.get();
}
catch(Exception e) {
//do some calculations here and then throw exception
throw new Exception(e.getMessage(), e);
}
}
}
public static <R> CompletableFuture<R> callAsync(Callable<R> callable, Executor e) {
CompletableFuture<R> cf = new CompletableFuture<>();
CompletableFuture.runAsync(() -> {
try { cf.complete(callable.call()); }
catch(Throwable ex) { cf.completeExceptionally(ex); }
}, e);
return cf;
}
So we have no invokeAll which takes care of submitting all jobs. We have to do this manually, either with a loop or a stream operation. On the other hand, we get a single future via allOf representing the completion status, exceptionally if at least one job failed.
Unlike invokeAll, which waits for the completion, allOf only returns the future so it is the all.get() call which waits for the completion. We could do other things before it or even use this property to always perform the first job in the caller thread:
public static void execute(List<Callable<Boolean>> threadList) throws Exception {
CompletableFuture<?> tail = CompletableFuture.allOf(
threadList.stream().skip(1)
.map(c -> callAsync(c, myThreadPoolExecutor))
.toArray(CompletableFuture<?>[]::new)),
head = callAsync(threadList.get(0), Runnable::run);
try {
head.get();
tail.get();
}
catch(Exception e) {
//do some calculations here and then throw exception
throw new Exception(e.getMessage(), e);
}
}
This will always call the first callable in the current thread, as Runnable::run used as Executor will perform the action immediately in the calling thread. But it's treated uniformly in all other aspects, especially the exception handling. When there is only one job, allOf invoke with an empty array will do nothing and return an already completed future, which will have the desired effect.
Future.isDone() tells us if the executor has finished processing the task. If the task is completed, it will return true otherwise, it returns false.
for (Future<Boolean> future : futureList) {
while(!future.isDone())
{
doSOmethingElse();
Thread.sleep(300);//Optional
}
try {
future.get();
}
catch (Exception e)
{
//do some calculations here and then throw exception
throw new Exception(e.getMessage(), e);
}
}
But we don't have to worry about that since we get to the point where get() is called after making sure that the task is finished.
I execute a few callables through ThreadPoolExecutor. If thread list contains only 1 callable then I directly call call method of my CallableService. If list contains more than 1 callables then I execute all those threads in parallel via thread pool executor.
I guess you have already implemented this part. (You might run into memory usage issues if your jobs are heavy and you have 100 threads running as configured. But that is a different problem.)
And if future.get() is enhanced to avoid blocking, that will be a plus.
For this, you may take this approach:
Create another ExecutorService whose job will be just to run the Future.get() calls.
Submit your Future.get() to that service as shown below.
Shut it down and await termination.
if (null != futureList) {
ExecutorService waitSvc = Executors.newCachedThreadPool();
for (Future<Boolean> future : futureList) {
try {
waitSvc.submit( () -> future.get() );
}
catch (Exception e) {
//do some calculations here and then throw exception
throw new Exception(e.getMessage(), e);
}
}
waitSvc.shutdown(); //This may take some time. You may want to call awaitTermination() after this.
}
However, I feel that you should redesign the overall approach of using so many threads, unless this is only a for-learning application.

Detecting a timeout exception on a Java Future without calling get() on it

I am building a library that needs to some bluetooth operations on Android. I want to return a Future instance, so whoever is using my library can call .get() on the future returned and can handle ExecutionException, TimeoutException and InterruptedException themselves. However, I want to detect a timeout myself because I need to some cleanup logic like disconnecting from the device and so on. How can I achieve this?
You could implement a wrapper class around Future which delegates to a different one (the one returned by wherever you're getting your Future at the moment). Something like:
final class DelegatingFuture<T> implements Future<T> {
private final Future<T> delegate;
DelegatingFuture(final Future<T> delegate) {
this.delegate = Objects.requireNonNull(delegate);
}
// All other methods simply delegate to 'delegate'
#Override
public T get()
throws InterruptedException, ExecutionException {
try {
return this.delegate.get();
} catch (final Exception ex) {
// Handle cleanup...
throw ex;
}
}
// Something similar for get(long timeout, TimeUnit unit)
}
And then simply return new DelegatingFuture<>(currentFuture); wherever your handing these out.
The timeout is relevant to the caller of the get method with timeout and only to that caller. A timeout is nowhere meant to imply a cancellation. E.g., the following code is a legitimate usage of the Future API:
ExecutorService es = Executors.newSingleThreadExecutor();
Future<String> f = es.submit(() -> {
Thread.sleep(3000);
return "hello";
});
for(;;) try {
String s = f.get(500, TimeUnit.MILLISECONDS);
System.out.println("got "+s);
break;
}
catch(TimeoutException ex) {
// perhaps, do some other work
System.out.println("will wait something more");
}
catch (ExecutionException ex) {
System.out.println("failed with "+ex);
break;
}
es.shutdown();
Tying the cleanup to the methods actually intended to query the result, is not a useful approach. The timeout provided by the caller(s) of that method do not relate to the actual operation. There’s not even a guaranty that the result will be queried before the operations ends or that it gets queried at all.
The cleanup should happen when either, the operation finished or when the future gets cancelled explicitly. If the caller intends a cancellation after a timeout, the caller only needs to invoke cancel after catching a TimeoutException.
One approach, often pointed to, is to use a CompletionService, e.g.
static final ExecutorService MY__EXECUTOR = Executors.newCachedThreadPool();
static final CompletionService<String> COMPLETION_SERVICE
= new ExecutorCompletionService<>(MY__EXECUTOR);
static final Future<?> CLEANER = MY__EXECUTOR.submit(() -> {
for(;;) try {
Future<String> completed = COMPLETION_SERVICE.take();
System.out.println("cleanup "+completed);
} catch(InterruptedException ex) {
if(MY__EXECUTOR.isShutdown()) break;
}
});
public static Future<String> doSomeWork() {
return COMPLETION_SERVICE.submit(() -> {
Thread.sleep(3000);
return "hello";
});
}
You are in control over when to poll the completed futures, like in another background thread, as shown in the example, or right before commencing new jobs.
You can test it like
Future<String> f = doSomeWork();
try {
String s = f.get(500, TimeUnit.MILLISECONDS);
System.out.println("got "+s);
}
catch(TimeoutException ex) {
System.out.println("no result after 500ms");
}
catch (ExecutionException ex) {
System.out.println("failed with "+ex);
}
if(f.cancel(true)) System.out.println("canceled");
f = doSomeWork();
// never calling get() at all
But honestly, I never understood why such complicated things are actually necessary. If you want a cleanup at the right time, you can use
static final ExecutorService MY__EXECUTOR = Executors.newCachedThreadPool();
public static Future<String> doSomeWork() {
Callable<String> actualJob = () -> {
Thread.sleep(3000);
return "hello";
};
FutureTask<String> ft = new FutureTask<>(actualJob) {
#Override
protected void done() {
System.out.println("cleanup "+this);
}
};
MY__EXECUTOR.execute(ft);
return ft;
}
to achieve the same.
Or even simpler
static final ExecutorService MY__EXECUTOR = Executors.newCachedThreadPool();
public static Future<String> doSomeWork() {
Callable<String> actualJob = () -> {
Thread.sleep(3000);
return "hello";
};
return MY__EXECUTOR.submit(() -> {
try {
return actualJob.call();
}
finally {
// perform cleanup
System.out.println("cleanup");
}
});
}
In either case, the cleanup will be performed whether the job was completed successfully, failed, or got canceled. If cancel(true) was used and the actual job supports interruption, the cleanup also will be performed immediately after.

Catching thread exceptions from Java ExecutorService

I'm working on a software development framework for parallel computing JavaSeis.org. I need a robust mechanism for reporting thread exceptions. During development, knowing where exceptions came from has high value, so I would like to err on the side of over-reporting. I would also like to be able to handle Junit4 testing in threads as well. Is the approach below reasonable or is there a better way ?
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TestThreadFailure {
public static void main(String[] args) {
int size = 1;
ExecutorService exec = Executors.newFixedThreadPool(size);
ThreadFailTask worker = new ThreadFailTask();
Future<Integer> result = exec.submit(worker);
try {
Integer value = result.get();
System.out.println("Result: " + value);
} catch (Throwable t) {
System.out.println("Caught failure: " + t.toString());
exec.shutdownNow();
System.out.println("Stack Trace:");
t.printStackTrace();
return;
}
throw new RuntimeException("Did not catch failure !!");
}
public static class ThreadFailTask implements Callable<Integer> {
#Override
public Integer call() {
int nbuf = 65536;
double[][] buf = new double[nbuf][nbuf];
return new Integer((int) buf[0][0]);
}
}
}
Consider calling execute() instead of submit() on the ExecutorService. A Thread invoked with execute() will invoke the Thread.UncaughtExceptionHandler when it fails.
Simply make a ThreadFactory that installs a Thread.UncaughtExceptionHandler on all Threads and then invoke your work with execute() on the ExecutorService instead of submit().
Have a look at this related stack overflow question.
I don't believe there is a standard 'hook' to get to these exceptions when using submit(). However, if you need to support submit() (which sounds reasonable, given that you use a Callable), you can always wrap the Callables and Runnables :
ExecutorService executor = new ThreadPoolExecutor(1, 10, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>()) {
#Override
public <T> Future<T> submit(final Callable<T> task) {
Callable<T> wrappedTask = new Callable<T>() {
#Override
public T call() throws Exception {
try {
return task.call();
}
catch (Exception e) {
System.out.println("Oh boy, something broke!");
e.printStackTrace();
throw e;
}
}
};
return super.submit(wrappedTask);
}
};
Of course, this method only works if you're the one building the ExecutorService in the first place. Furthermore, remember to override all three submit() variants.
As explained in this thread What is the difference between submit and execute method with ThreadPoolExecutor, using execute will only work if you implement Runnable and not Callable as execute cannot return a Future.
I think in your scenario you should build the future object so that it can accommodate the exception stuff also. So in case of exception you build the error message object.
My original question asked how to implement "robust" thread exception handling with Java ExecutorService. Thanks to Angelo and Greg for pointers on how exception handling works with ExecutorService.submit() and Future.get(). My revised code fragment is shown below. The key point I learned here is that Future.get() catches all exceptions. If the the thread was interrupted or cancelled, you get the appropriate exception, otherwise, the exception is wrapped and re-thrown as an ExecutionException.
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TestThreadFailure {
public static void main(String[] args) {
int size = 1;
ExecutorService exec = Executors.newFixedThreadPool(size);
ThreadFailTask worker = new ThreadFailTask();
Future result = exec.submit(worker);
try {
Integer value = result.get();
System.out.println("Result: " + value);
} catch (ExecutionException ex) {
System.out.println("Caught failure: " + ex.toString());
exec.shutdownNow();
return;
} catch (InterruptedException iex) {
System.out.println("Thread interrupted: " + iex.toString());
} catch (CancellationException cex) {
System.out.println("Thread cancelled: " + cex.toString());
}
exec.shutdownNow();
throw new RuntimeException("Did not catch failure !!");
}
public static class ThreadFailTask implements Callable {
#Override
public Integer call() {
int nbuf = 65536;
double[][] buf = new double[nbuf][nbuf];
return new Integer((int) buf[0][0]);
}
}
}
I didn't have a great deal of luck with other answers because I needed the actual exception instance, itself, not just a printed stack trace. For me, the accepted answer involving ThreadPoolExecutor#afterExecute() of the question "Why is UncaughtExceptionHandler not called by ExecutorService?" worked.
See the following sample code:
List<Runnable> tasks = new LinkedList<>();
for (int i = 0; i < numThreads; ++i) {
Runnable task = new Runnable() {
#Override
public void run() {
throw new RuntimeException();
}
};
tasks.add(task);
}
Optional<Throwable> opEmpty = Optional.empty();
/*
* Use AtomicReference as a means of capturing the first thrown exception, since a
* spawned thread can't "throw" an exception to the parent thread.
*/
final AtomicReference<Optional<Throwable>> firstThrownException =
new AtomicReference<>(opEmpty);
/*
* Use new ThreadPoolExecutor instead of Executors.newFixedThreadPool() so
* that I can override afterExecute() for the purposes of throwing an
* exception from the test thread if a child thread fails.
*/
ExecutorService execSvc = new ThreadPoolExecutor(numThreads, numThreads,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()) {
#Override
public void afterExecute(Runnable task, Throwable failureCause) {
if(failureCause == null) {
// The Runnable completed successfully.
return;
}
// only sets the first exception because it will only be empty on the first call.
firstThrownException.compareAndSet(Optional.<Throwable>empty(), Optional.of(failureCause));
}
};
for (Runnable task : tasks) {
execSvc.execute(task);
}
execSvc.shutdown();
execSvc.awaitTermination(1, TimeUnit.HOURS);
assertEquals(firstThrownException.get(), Optional.empty());
To Handling exceptions in ExecutorService you have to take the advantage of Callable and Future.
Callable is similar to Runnable and both are functional interface but run() of Runnable doesn't throws exception and the return type is void where as call() of Callable returns a generics and throws exception.
Java-8 way:
ExecuterService executor = null;
Future<Integer> future = null;
Callable<Integer> yourTask = () -> {
//your implementation here();
//your implementation here();
};
try
{
executor = Executors.newCachedThreadPool();
future = executor.submit(yourTask );
Integer result = future.get();
System.out.println(result);
}
catch (ExecutionException | TimeoutException | InterruptedException e)
{
// TODO: handle exception
}
finally
{
executer.shutdown();
}

Categories

Resources