diff --git a/lucene/core/src/java/org/apache/lucene/search/TaskExecutor.java b/lucene/core/src/java/org/apache/lucene/search/TaskExecutor.java index 9d2176fd3af..331d692a854 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TaskExecutor.java +++ b/lucene/core/src/java/org/apache/lucene/search/TaskExecutor.java @@ -110,21 +110,23 @@ public final class TaskExecutor { } RunnableFuture createTask(Callable callable) { - AtomicBoolean startedOrCancelled = new AtomicBoolean(false); - return new FutureTask<>( - () -> { - if (startedOrCancelled.compareAndSet(false, true)) { - try { - return callable.call(); - } catch (Throwable t) { - cancelAll(); - throw t; - } - } - // task is cancelled hence it has no results to return. That's fine: they would be - // ignored anyway. - return null; - }) { + return new FutureTask<>(callable) { + + private final AtomicBoolean startedOrCancelled = new AtomicBoolean(false); + + @Override + public void run() { + if (startedOrCancelled.compareAndSet(false, true)) { + super.run(); + } + } + + @Override + protected void setException(Throwable t) { + super.setException(t); + cancelAll(); + } + @Override public boolean cancel(boolean mayInterruptIfRunning) { assert mayInterruptIfRunning == false @@ -136,7 +138,13 @@ public final class TaskExecutor { wait for them to finish instead of throwing CancellationException. A cleaner way would have been to override FutureTask#get and make it wait for cancelled tasks, but FutureTask#awaitDone is private. Tasks that are cancelled before they are started will be no-op. */ - return startedOrCancelled.compareAndSet(false, true); + if (startedOrCancelled.compareAndSet(false, true)) { + // task is cancelled hence it has no results to return. That's fine: they would be + // ignored anyway. + set(null); + return true; + } + return false; } }; }