正确覆盖CompletableFuture.cancel

问题描述 投票:3回答:2

我注意到,如果将来调用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
}

java completable-future
2个回答
3
投票

您需要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,取消与CancellationException的特殊完成没有区别。因此,有人可以调用completeExceptionally(new CancellationException())而不是cancel(...),以达到相同的效果。


1
投票

没有直接的方法可以执行所需的操作,因为thenApply返回一个新的CompletableFuture对象。但是,如果确实需要执行此操作,则可以尝试覆盖CompletableFuture类本身。

让我解释一下!CompletableFuture.thenApply()方法还调用uniApplyStage类的CompletableFuture私有方法,其中创建了new CompletableFuture()实例以返回。 (我反编译了Java源代码以进行检查。)

您不能覆盖此方法,因为它是私有方法。但是,如果您;

  1. 反编译类CompletableFuture
  2. 复制代码。
  3. 在创建uniApplyStage实例时将@Override方法从cancel更改为new CompletableFuture<V>()
  4. 然后在运行时,按照https://stackoverflow.com/a/6680889/11226302中提到的步骤,使用“自定义ClassLoader”在运行时重新加载类。

从理论上讲,您应该能够完成所有这一切。

但是,问题仍然存在。您多么想完成这项工作? :D

根据我的诚实观点,将此答案视为最后的选择。

© www.soinside.com 2019 - 2024. All rights reserved.