Handling Exceptions from Java Executorservice Tasks

Handling exceptions from Java ExecutorService tasks

From the docs:

Note: When actions are enclosed in
tasks (such as FutureTask) either
explicitly or via methods such as
submit, these task objects catch and
maintain computational exceptions, and
so they do not cause abrupt
termination, and the internal
exceptions are not passed to this
method.

When you submit a Runnable, it'll get wrapped in a Future.

Your afterExecute should be something like this:

public final class ExtendedExecutor extends ThreadPoolExecutor {

// ...

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) {
System.out.println(t);
}
}
}

exception handling in executor service

You can move around the try/catch:

Original:

try {
List<Future<String>> resultList=executor.invokeAll(list);
for(Future<String> f:resultList){
// if(f.isDone()){

System.out.println(f.get());

//}
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (ExecutionException e) {
// TODO Auto-generated catch block
System.out.println("HELLO SOME ERROR");
// e.printStackTrace();
}

will be rather:

try {
List<Future<String>> resultList=executor.invokeAll(list);
for(Future<String> f:resultList){
try{
System.out.println(f.get());
}catch (ExecutionException e) {
System.out.println("HELLO SOME ERROR: " + e.getMessage());
}
} catch (InterruptedException e) {
e.printStackTrace();
}

So here you will get all OK results and you can handle the exceptional execution for each task.

Catching thread exceptions from Java ExecutorService

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.

How to retrieve and handle exceptions in Java's ExecutorService

you could trigger all your tasks within one loop and check/await/retry in another:

Map<Future<?>, Task> futures = new HashMap<Future<?>, Task>()
while(!taskQueue.isEmpty()){
Task task = taskQueue.poll();
Future<?> future = executor.submit(task);
futures.put(future, task);
}

for(Map.Entry<Future<?>, Task> entry : futures.entrySet()){

try {
entry.getKey().get();
}
catch(ExecutionException ex) {
// record the failed task, so that it can be re-added to the queue
// you should add a retry counter because you want to prevent endless loops
taskQueue.add(entry.getValue());
}
catch(InterrupredException ex){
// thread interrupted, exit
Thread.interrupt();
return;
}
}

HTH, Mark

How to handle exception thrown by an ExecutorService task?

Calling get() on the completed futureTask_1 will throw an ExecutionException typically wrapping the cause when the task threw some exception.

Stop ExecutorService on thread failure and exception handling

You can do that using CompletableFuture. This is your main function I tested:

final ExecutorService executorService = Executors.newFixedThreadPool(4);
final List<CompletableFuture<Void>> all = new ArrayList<>();

try {
for (int i = 0; i < 10; i++) {
int b = i;
CompletableFuture<Void> v = CompletableFuture.runAsync(() -> {
try {
doSomeWork(b);
} catch (Exception e) {
throw new RuntimeException(e);
}
},
executorService);
all.add(v);
}

CompletableFuture<Void> placeholder = CompletableFuture.allOf(all.toArray(new CompletableFuture[0]));
failFast(all, placeholder);

System.out.println("All tasks ended");

} catch (Exception e) {
System.out.println("Something wrong happened: " + e.getMessage());
} finally {
executorService.shutdownNow();
}

Utility function to make the joint future fail as soon as one of them is failed (or when all of them are completed):

private static <T> void failFast(List<CompletableFuture<T>> futures, CompletableFuture<T> joint) {
while (true) {
if (joint.isDone()) {
return;
}
for (CompletableFuture<T> future : futures) {
if (future.isCompletedExceptionally()) {
return;
}
}
}
}

And this is the output I get:

I have reached indice: 1
I have reached indice: 7
I have reached indice: 5
I have reached indice: 4
Something wrong happened: java.lang.RuntimeException: java.lang.Exception: I couldn't handle indice 0

Explanation:

The method CompletableFuture.runAsync() allows you to provide with a Runnable (your doSomeWork) and an executor with a certain number of threads. Here, I pass an executor with 4 threads (as you did in your example).

Inside the runnable, I don't only run the doSomeWork function but I also catch Exception and throw a RuntimeException (need to do that because Lambdas do not support checked exceptions, so I need to wrap it into a runtime one but it will still interrupt execution and be catched by your main).

Each time I create a new CompletableFuture<Void> for the task with the given index i, I will store this result into a list of completable futures.

The for loop will take nothing to execute, since the completable futures run asynchronously.

Hence, I create a joint completable future with CompletableFuture.allOf(...) and then I use the utility function failFast on this future in order to stop as soon as one of the task is failed (or to continue until all of them are complete).

So basically as soon as one of the futures fails throwing an exception, the joint future is considered to be completed and will hence leave the handle to your main thread which is, meanwhile, being hit by the RuntimeException that was thrown inside the lambda expression.

Note: thanks to Thomas' comment, I've updated the code to use an ExecutorService instead of a simple Executor. That allows you to have a call to shutdownNow() inside your finally block after you catch the exception.
As Thomas suggests, also, you may directly throw a RuntimeException inside your doSomeWork function so you don't need to catch and wrap inside the lambda expression.

Other note: @matt made me notice something I didn't know. The .allOf() future will be completed when ALL futures are completed, whether successfully or not.
Hence, as he pointed out, my solution wouldn't work as is. I've edited again the answer to take his comment into account, thanks @matt for making me notice.

ExecutorService that rethrows exceptions

I don't think it is possible to do this with simply using Executors.

You can consider using a try-catch block in your Task and add the exception on to a queue in the catch block.

try{
//perform task
}catch(Exception e){
queue.offer(e)
}

Create a thread that reads the exception from the queue.

public void run() {
Exception e;
try {
e = q.take();
e.printStackTrace();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
}
}

ScheduledExecutorService Exception handling

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();
}

Recover from exceptions in ExecutorService

Try catching exception within your loop like below:

ExecutorService service = Executors.newSingleThreadExecutor();
service.submit(new Runnable(){
public void run(){
while(true){
try {
doSomething();
} catch (Exception e) {
//log exception etc...
}
}
}
});


Related Topics



Leave a reply



Submit