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");
Related
I am trying to make my Thread sleep and am making the method throws InterruptedException, however it is still giving the error "Unhandled exception"
#Before
public void setUp() throws InterruptedException{
simulatorList.forEach(simulation -> {
....
Thread.sleep(1000*60*1);
//giving error here
...
});
}
Because you calling Thread.sleep inside foreach, Below will solve your issue:
public void setUp() throws InterruptedException {
List<String> simulatorList = new ArrayList<>();
for (String s : simulatorList) {
Thread.sleep(1000 * 60 * 1);
}
}
Cause exception can be thrown from lambda. The easiest way to handle it is to rethrow the RuntimeException. like
public void setUp(){
new LinkedList<String>().forEach(simulation -> {
try {
Thread.sleep(1000*60*1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
}
If you really expect for InterruptedException, you can create your own exception extending RuntimeException, like RuntimeInterruptedException, rethrow it and then handle in your flow.
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);
}
}
};
A runnable task parses incoming xml file and is invoked from a different class. Sometimes the parsing may fail and throw an exception. The task should be running even when exceptions occur. I tried restarting the same task in a new thread using Uncaught exception handler. But wanted more ideas on that.
Class invoking thread : (invokes thread)
It works fine to restart same task in new thread but probably handling exceptions without leading to a thread exit should be the way
Thread fileProcessThread = new Thread(FileProcessor);
fileProcessorThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler()
{
#Override
public void uncaughtException (Thread arg0, Throwable arg1)
{
FileProcessor newObject = new FileProcessorTask();
Thread t = new Thread(newObject);
t.start();
}
});
fileProcessor.start();
Task Class :
public void run() {
try {
xmlparser.parse(incomingXmlFile);
}
catch (Exception e) {
Thread.currentThread.getUncaughtExceptionalHandler().uncaughtException(Thread.currentThread(), e);
// this invokes uncaughtException to restart thread ?
}
}
I have a watch service (file directory scan) running, so I need the task all the time, even if thread terminates.
When an exception occurs and call reaches the uncaughtExceptionHandler, the state of the thread is Invalid to start again. So you need to create a new thread and start again.
Code from Thread.start()
// A zero status value corresponds to state "NEW".
if (threadStatus != 0)
throw new IllegalThreadStateException();
However this could easily result in an infinite loop. (exception -> catch -> retry -> exception -> catch ...)
I recommend having a counter which stops the retries after a certain point.
Public class TestClass{
static AtomicInteger counter = new AtomicInteger();
static class MyExceptionHandler implements UncaughtExceptionHandler {
#Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("caught");
if (counter.get() == 3) {
System.out.println("Reached Max. retries, exiting");
} else {
counter.incrementAndGet();
new Thread(new MyTask()).start();
}
}
}
static class MyTask implements Runnable {
#Override
public void run() {
try {
Thread.currentThread().setUncaughtExceptionHandler(new MyExceptionHandler());
System.out.println("slept");
Thread.sleep(500);
double d = 0 / 0;
} catch (InterruptedException e) {}
}
}
public static void main(String args[]) throws Exception {
Thread thread = new Thread(new MyTask());
thread.start();
}
}
I've used static AtomicInteger but in your implementation probably have a common object which can be passed on from one thread to another and let that object have a counter.
Consider this code:
Thread.setDefaultUncaughtExceptionHandler((Thread t, Throwable e) -> {
System.out.println("An exception occurred!");
});
// set the exception handler for the JavaFX application thread
Thread.currentThread().setUncaughtExceptionHandler((Thread t, Throwable e) -> {
System.out.println("An exception occurred!");
});
Task<?> task = new Task() {
#Override
public Void call() throws Exception {
throw new RuntimeException("foobar");
};
};
new Thread(task).start();
If we run the code the runtime exception never triggers the default exception handler but is instead consumed by the task. The only way to counteract this that I found is to rethrow the exception in task.setOnFailed:
task.setOnFailed((WorkerStateEvent t) -> {
throw new RuntimeException(task.getException());
});
Since JavaFX 8 now has support for the UncaughtExceptionHandler why isn't the exception propagated to the exception handler?
Inside the Task.call() method just throw the exception and add a ChangeListener to the task like this:
task.exceptionProperty().addListener((observable, oldValue, newValue) -> {
if(newValue != null) {
Exception ex = (Exception) newValue;
ex.printStackTrace();
}
});
Then, after the task failed with the exception, you get notified by the listener which exception was thrown during execution. You can easily exchange the line ex.printStackTrace(); with an Alert if you are in the JavaFX Execution Thread.
Feature, Task maintains an exception property itself. The idea is, that when an exception is thrown, the tasks fails, and one may ask which exception was thrown. In that respect Task was conceived as a quasi batch job, running in the background, and possibly silently failing.
That reflects also a bit of the asynchrone behaviour; where the exception could be handled. Not at the place where start was called.
A bit late probably but you can print the throwable itself:
task.setOnFailed(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent arg0) {
Throwable throwable = task.getException();
throwable.printStackTrace();
}
}
The exceptions gets thrown anyway, but you can use this to display it to the user or log it.
I know that this question is old, but I searched for an answer and have not found very much about this topic. I think you can rethrow the exception if you like to do so. Here is the sample code:
public class Main extends Application {
#Override
public void start(Stage stage) {
Task<Void> task = new Task<Void>() {
#Override
protected Void call() throws Exception {
throw new IndexOutOfBoundsException();
}
};
task.setOnSucceeded(evt -> System.out.println("Task succeeded!"));
task.setOnCancelled(evt -> System.out.println("Task cancelled!"));
task.setOnFailed(evt -> {
System.out.println("Task failed!");
if (task.getException() instanceof IndexOutOfBoundsException) {
System.out.println("...with an IndexOutOfBoundsException");
} else if (task.getException() instanceof NumberFormatException) {
System.out.println("...with a NumberFormatException");
} else {
System.out.println("...with another, unexpected execption");
}
});
VBox box = new VBox();
Scene scene = new Scene(box, 200, 200);
stage.setScene(scene);
stage.setTitle("Thread Example");
stage.show();
new Thread(task).start();
}
public static void main(String[] args) {
launch(args);
}
}
Console-Output:
Task failed!
...with a IndexOutOfBoundsException
If an exception is thrown inside a task, then the task ends up in the state 'failed'. In the setOnFailed method you can handle the failure of the task. All code inside this method is on the application thread of JavaFX but you can rely on the exception of the task by task.getException(). Besides, this code only works with JavaFX (I tried to get the same output in a normal java app, but it did not work out).
It boils down to one thread submitting job via some service. Job is executed in some TPExecutor. Afterwards this service checks for results and throw exception in original thread under certain conditions (job exceeds maximum number of retries, etc.). Code snippet below roughly illustrate this scenario in legacy code:
import java.util.concurrent.CountDownLatch;
public class IncorrectLockingExample {
private static class Request {
private final CountDownLatch latch = new CountDownLatch(1);
private Throwable throwable;
public void await() {
try {
latch.await();
} catch (InterruptedException ignoredForDemoPurposes) {
}
}
public void countDown() {
latch.countDown();
}
public Throwable getThrowable() {
return throwable;
}
public void setThrowable(Throwable throwable) {
this.throwable = throwable;
}
}
private static final Request wrapper = new Request();
public static void main(String[] args) throws InterruptedException {
final Thread blockedThread = new Thread() {
public void run() {
wrapper.await();
synchronized (wrapper) {
if (wrapper.getThrowable() != null)
throw new RuntimeException(wrapper.getThrowable());
}
}
};
final Thread workingThread = new Thread() {
public void run() {
wrapper.setThrowable(new RuntimeException());
wrapper.countDown();
}
};
blockedThread.start();
workingThread.start();
blockedThread.join();
workingThread.join();
}
}
Sometimes, (not reproducible on my box, but happens on 16 core server box) exception isn't getting reported to original thread. I think this is because happens-before is not forced(eg. 'countDown' happens before 'setThrowable') and program continues to work(but should fail).
I would appreciate any help about how to resolve this case.
Constraints are: release in a week, minimum impact on existing codebase is needed.
The code above (as now updated) should work as you expected without the use of further synchronisation mechanisms. The memory barrier and its corresponding 'happens-before' relationship is enforced by the use of the CountDownLatch await() and countdown() methods.
From the API docs:
Actions prior to "releasing" synchronizer methods such as Lock.unlock, Semaphore.release, and CountDownLatch.countDown happen-before actions subsequent to a successful "acquiring" method such as Lock.lock, Semaphore.acquire, Condition.await, and CountDownLatch.await on the same synchronizer object in another thread.
If you are dealing with concurrency on a regular basis get yourself a copy of 'Java Concurrency in Practice', it's the Java concurrency bible and will be well worth its weight on your bookshelf :-).
I suspect you need
private volatile Throwable throwable
Have you tried using an ExecutorService as it is built in and does this for you. The following prints
future1 := result
future2 threw java.lang.IllegalStateException
future3 timed out
The code is
public static void main(String... args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future1 = executor.submit(new Callable<String>() {
public String call() throws Exception {
return "result";
}
});
Future<String> future2 = executor.submit(new Callable<String>() {
public String call() throws Exception {
throw new IllegalStateException();
}
});
Future<String> future3 = executor.submit(new Callable<String>() {
public String call() throws Exception {
Thread.sleep(2000);
throw new AssertionError();
}
});
printResult("future1", future1);
printResult("future2", future2);
printResult("future3", future3);
executor.shutdown();
}
private static void printResult(String description, Future<String> future) {
try {
System.out.println(description+" := "+future.get(1, TimeUnit.SECONDS));
} catch (InterruptedException e) {
System.out.println(description+" interrupted");
} catch (ExecutionException e) {
System.out.println(description+" threw "+e.getCause());
} catch (TimeoutException e) {
System.out.println(description+" timed out");
}
}
In the code for FutureTask, there is a comment.
/**
* The thread running task. When nulled after set/cancel, this
* indicates that the results are accessible. Must be
* volatile, to ensure visibility upon completion.
*/
If you are not going to re-use the code in the JDK, it can still be worth reading it so you can pick up on any tricks they use.