首页 > 解决方案 > 正确覆盖 CompletableFuture.cancel

问题描述

我注意到如果将来调用该方法,则覆盖该cancel方法无效。thenApply派生的未来不知道原来有这样一个覆盖的事实。下面的代码演示了这个问题。

有什么方法可以正确地覆盖该方法而不会失去改变未来的可能性?

import java.util.concurrent.CompletableFuture;

public class Main {
    public static void main(String[] args){
        CompletableFuture<Object> unmodified = new CompletableFuture<>(){
            @Override
            public boolean cancel(boolean mayInterruptIfRunning) {
                System.out.println("----> cancelling unmodified");
                return super.cancel(mayInterruptIfRunning);
            }
        };
        unmodified
                .cancel(true);


        CompletableFuture<Object> modified = new CompletableFuture<>(){
            @Override
            public boolean cancel(boolean mayInterruptIfRunning) {
                System.out.println("----> cancelling modified");
                return super.cancel(mayInterruptIfRunning);
            }
        };
        unmodified
                .thenApply(x -> x)
                .cancel(true);
        System.out.println("----> end");
    }
    // OUTPUT
    // > Task :Main.main()
    // ----> cancelling unmodified
    // ----> end
}

标签: javacompletable-future

解决方案


您需要 Java 9 或更高版本。然后,所有创建新依赖未来的方法都将调用工厂方法newIncompleteFuture(),您可以覆盖它:

public static void main(String arg[]) {
    class MyFuture<T> extends CompletableFuture<T> {
        @Override
        public boolean cancel(boolean mayInterruptIfRunning) {
            System.out.println("customized cancel");
            return super.cancel(mayInterruptIfRunning);
        }

        @Override
        public <U> CompletableFuture<U> newIncompleteFuture() {
            return new MyFuture<>();
        }
    }
    MyFuture<Object> future = new MyFuture<>();

    System.out.print("direct: ");
    future.cancel(true);

    System.out.print("indirect: ");
    future.thenApply(x -> x).cancel(true);

    System.out.print("even longer chain: ");
    future.thenApply(x -> x).exceptionally(t -> null).cancel(true);

    System.out.println("end");
}
direct: customized cancel
indirect: customized cancel
even longer chain: customized cancel
end

但请记住,对于CompletableFuture,取消与带有 a 的异常完成没有什么不同CancellationException。所以,有人可以打电话completeExceptionally(new CancellationException())而不是cancel(...), 达到同样的效果。


推荐阅读