java.util.concurrent.ExecutorCompletionService
You can use ExecutorCompletionService for that. Here is a little example. Let's first create a simple ExecuteJob class for demonstration.
ExecuteJob.java
public class ExecuteJob implements Callable<String> {
private final int ID;
public ExecuteJob(int ID) {
this.ID = ID;
}
@Override
public String call() {
try {
Thread.sleep(1000L * this.ID);
// Let's fail the third thread for demonstration
// if (this.ID == 2) {
// throw new RuntimeException();
// }
return "OK\t" + (System.currentTimeMillis() / 1000);
} catch (Exception e) {
return "NOT OK\t" + (System.currentTimeMillis() / 1000);
}
}
}
This class when executed, sleeps for ID seconds to mimic a running job. I will explain the commented out part later.
App.java
private final static int iNumThread = 6;
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService es = Executors.newFixedThreadPool(iNumThread);
ExecutorCompletionService<String> ecs = new ExecutorCompletionService<>(es);
for (int i = 0; i < iNumThread; i++) ecs.submit(new ExecuteJob(i));
for (int i = 0; i < iNumThread; i++) {
Future<String> f = ecs.take(); // returns as soon as any task finishes
String result = f.get();
System.out.println(result);
if (!result.startsWith("OK")) {
System.out.println("One thread failed, cancelling all threads...");
es.shutdownNow();
break;
}
}
System.out.println("Gracefully shutting down threads...");
es.shutdown();
}
Here you can see that we use ExecutorCompletionService for execution of our tasks. submit() method sends a task to run in the background and immediately returns a Future you can use to get its result or cancel it.
Now when we run this code as is (there is a commented out part on ExecuteJob.java) the output is like this:
OK 1763043309
OK 1763043310
OK 1763043311
OK 1763043312
OK 1763043313
OK 1763043314
Gracefully shutting down threads...
Process finished with exit code 0
There is one second delay between each thread (because of the Thread.sleep() on the ExecutorJob, these are still running asynchronous). Let's un-comment those lines at the ExecutorJob and see what happens.
OK 1763043471
OK 1763043472
NOT OK 1763043473
One thread failed, cancelling all threads...
Gracefully shutting down threads...
Process finished with exit code 0
Now when we purposely shut down a thread (the third one) the program doesn't wait for rest of them and shuts all of the threads. Note that ExecutorService.shutdown() method gracefully shuts down the threads. As it says in the docs:
Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.
ExecutorService.shutdownNow() on the other hand executes all threads immediatelly.
Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution. This method does not wait for actively executing tasks to terminate.
I hope this answers your question. I may have skip some try/catch for the simplicity of the answer. You should use them in your code. Feel free to ask any question.
CompletableFuture. You can then useCompletableFuture.anyOfto wait. see