7 years later, I stumbled upon ExecutorService.invokeAny
, which does exactly what I want:
Executes the given tasks, returning the result of one that has completed successfully (i.e., without throwing an exception), if any do (before the given timeout elapses).
Upon normal or exceptional return, tasks that have not completed are cancelled.
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException;
<T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
Implementation sketch:
class LabyrinthGenerator implements Callable<Labyrinth> {
private static final int N = 16;
private static final ExecutorService pool = Executors.newFixedThreadPool(N);
public static Labyrinth generate() {
while (true) {
List<LabyrinthGenerator> generators = Stream.generate(LabyrinthGenerator::new)
.limit(N)
.collect(Collectors.toList());
try {
return pool.invokeAny(generators, 1, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException ex) {
// all attempts failed or timed out, try again
}
}
}
@Override
public Labyrinth call() throws Exception {
// ...
if (Thread.currentThread().isInterrupted()) {
// some other generator found a result, abort
}
// ...
}
}