diff --git a/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java b/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java index 45707cf9..337e1505 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java +++ b/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java @@ -3725,6 +3725,11 @@ public static > C cffuOrTimeout( * Unless all subsequent actions of dependent CompletableFutures is ensured executing async * (aka. the dependent CompletableFutures is created by async methods), using this method and {@link CompletableFuture#orTimeout(long, TimeUnit)} * is one less thread switch of task execution when triggered by timeout. + *

+ * Note: Before Java 21(Java 20-), {@link CompletableFuture#orTimeout(long, TimeUnit)} + * can leak if the future completes exceptionally, more info see + * JDK-8303742 + * and JDK bugfix commit. * * @param timeout how long to wait before completing exceptionally with a TimeoutException, in units of {@code unit} * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter @@ -3741,7 +3746,7 @@ public static > C orTimeout(C cfThis, long timeou } else { // below code is copied from CompletableFuture#orTimeout with small adoption if (!cfThis.isDone()) { - ScheduledFuture f = Delayer.delayToTimoutCf(cfThis, timeout, unit); + ScheduledFuture f = Delayer.delayToTimeoutCf(cfThis, timeout, unit); cfThis.whenComplete(new FutureCanceller(f)); } } diff --git a/cffu-core/src/main/java/io/foldright/cffu/DelayExecutionHelpers.java b/cffu-core/src/main/java/io/foldright/cffu/DelayExecutionHelpers.java index 43552b89..8f4325ff 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/DelayExecutionHelpers.java +++ b/cffu-core/src/main/java/io/foldright/cffu/DelayExecutionHelpers.java @@ -36,7 +36,7 @@ static ScheduledFuture delay(Runnable command, long delay, TimeUnit unit) { * @return a Future can be used to cancel the delayed task(timeout CF) * @see FutureCanceller */ - static ScheduledFuture delayToTimoutCf(CompletableFuture cf, long delay, TimeUnit unit) { + static ScheduledFuture delayToTimeoutCf(CompletableFuture cf, long delay, TimeUnit unit) { return delay(new CfTimeout(cf), delay, unit); } @@ -188,7 +188,7 @@ public void run() { * code is copied from {@link CompletableFuture.Canceller} with small adoption. * * @see Delayer#delay(Runnable, long, TimeUnit) - * @see Delayer#delayToTimoutCf(CompletableFuture, long, TimeUnit) + * @see Delayer#delayToTimeoutCf(CompletableFuture, long, TimeUnit) * @see Delayer#delayToCompleteCf(CompletableFuture, Object, long, TimeUnit) */ @SuppressWarnings("JavadocReference") @@ -202,7 +202,7 @@ final class FutureCanceller implements BiConsumer { @Override public void accept(Object ignore, @Nullable Throwable ex) { - if (ex == null && f != null && !f.isDone()) + if (f != null && !f.isDone()) f.cancel(false); } }