Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return to main thread as soon as one child thread throws an exception

I'm using Executors.newCachedThreadPool() and invokeAll with a List of Callables to do long-running multithreaded processing. My main thread is blocked until all threads did finish and I can process the Futures returned by invokeAll. I'd like however invokeAll to immediately return if one of the Callables throw an exception and terminate the other threads.

Using execute instead of invokeAll would block on the first future.get() which needs not to be the one that throws the execption.

Using busy waiting to loop through all the futures and checking isDone() seems not to be the best way either.

like image 346
stracktracer Avatar asked Jan 10 '13 18:01

stracktracer


People also ask

Can main thread exit before child?

Yes. "this gets printed before the system. out. println() in the child threads.

What happens when an exception is thrown by a thread?

An uncaught exception will cause the thread to exit. When it bubbles to the top of Thread. run() it will be handled by the Thread's UncaughtExceptionHandler. By default, this will merely print the stack trace to the console.

Which method is used to make main thread wait for child threads?

Explanation: By calling sleep() within main(), with long enough delay to ensure that all child threads terminate prior to the main thread. 2.


1 Answers

You can use more complex synchronization mechanisms like latches, barriers or semaphores, but have a look at ExecutorCompletionService. It's a lightweight wrapper around ExecutorService that allows you to listen for the first finished task. Here is a quick example:

final ExecutorService executorService = Executors.newCachedThreadPool();
final ExecutorCompletionService<String> completionService = 
            new ExecutorCompletionService<String>(executorService);
for (int i = 0; i < 10; ++i) {
    completionService.submit(new Task());
}
completionService.take().get();

The code is pretty simple. First you wrap executorService with completionService. Later you use it to submit tasks one after another. The last line is crucial. It takes the first task that finished and tries to retrieve the result. If it thrown an exception, it will be rethrown here, wrapped with ExecutionException:

try {
    completionService.take().get();
} catch (ExecutionException e) {
    e.getCause();       //this was thrown from task!
}

Inside catch block you can somehow handle the exception, e.g. canceling remaining tasks or shutting down the whole thread pool.

Of course you are free to wait for all tasks to finish by calling take() ten times. Each call will block as long as there is at least one task finished.

like image 160
Tomasz Nurkiewicz Avatar answered Oct 28 '22 15:10

Tomasz Nurkiewicz