将Java Future转换为CompletableFuture

时间:2014-04-25 19:38:28

标签: java java-8 future

Java 8引入了CompletableFuture,一个可组合的Future的新实现(包括一堆thenXxx方法)。我想独占使用它,但我想使用的许多库只返回不可组合的Future实例。

有没有办法在Future内包装一个返回的CompleteableFuture个实例,以便我可以编写它?

6 个答案:

答案 0 :(得分:48)

有一种方法,但你不会喜欢它。以下方法将Future<T>转换为CompletableFuture<T>

public static <T> CompletableFuture<T> makeCompletableFuture(Future<T> future) {
    return CompletableFuture.supplyAsync(() -> {
        try {
            return future.get();
        } catch (InterruptedException|ExecutionException e) {
            throw new RuntimeException(e);
        }
    });
}

显然,这种方法的问题是,对于每个 Future ,一个线程将被阻塞以等待 Future 的结果 - 与之相矛盾的是期货。在某些情况下,可能会做得更好。但是,一般情况下,如果没有主动等待 Future 的结果,就没有解决方案。

答案 1 :(得分:47)

如果您要使用的库除了Future样式之外还提供回调样式方法,您可以为它提供一个处理程序来完成CompletableFuture而不会有任何额外的线程阻塞。像这样:

    AsynchronousFileChannel open = AsynchronousFileChannel.open(Paths.get("/some/file"));
    // ... 
    CompletableFuture<ByteBuffer> completableFuture = new CompletableFuture<ByteBuffer>();
    open.read(buffer, position, null, new CompletionHandler<Integer, Void>() {
        @Override
        public void completed(Integer result, Void attachment) {
            completableFuture.complete(buffer);
        }

        @Override
        public void failed(Throwable exc, Void attachment) {
            completableFuture.completeExceptionally(exc);
        }
    });
    completableFuture.thenApply(...)

没有回调,我看到解决这个问题的另一种方法是使用一个轮询循环,将所有Future.isDone()个检查放在一个线程上,然后在Future可以获取时调用complete。

答案 2 :(得分:15)

如果您的Future是调用ExecutorService方法(例如submit())的结果,则最简单的方法是使用CompletableFuture.runAsync(Runnable, Executor)方法。

来自

Runnbale myTask = ... ;
Future<?> future = myExecutor.submit(myTask);

Runnbale myTask = ... ;
CompletableFuture<?> future = CompletableFuture.runAsync(myTask, myExecutor);

然后{n}创建CompletableFuture

编辑:通过@SamMefford进行评论,并通过@MartinAndersson进行更正,如果要传递Callable,则需要调用supplyAsync(),将Callable<T>转换为{{1} },例如与:

Supplier<T>

由于CompletableFuture.supplyAsync(() -> { try { return myCallable.call(); } catch (Exception ex) { throw new RuntimeException(ex); } // Or return default value }, myExecutor); 引发了异常而T Callable.call() throws Exception;没有引发异常,因此您必须捕获该异常,以便原型兼容。

答案 3 :(得分:7)

我发布了一个小futurity项目,试图在答案中优于the straightforward way

主要思想是使用唯一的一个线程(当然不仅仅是一个旋转循环)来检查里面的所有Futures状态,这有助于避免为每个Future阻止来自池的线程 - &gt; CompletableFuture转型。

用法示例:

Future oldFuture = ...;
CompletableFuture profit = Futurity.shift(oldFuture);

答案 4 :(得分:5)

让我建议另一个(希望,更好)选项: https://github.com/vsilaev/java-async-await/tree/master/com.farata.lang.async.examples/src/main/java/com/farata/concurrent

简而言之,这个想法如下:

  1. 介绍CompletableTask<V>接口 - 联合的 CompletionStage<V> + RunnableFuture<V>
  2. 翘曲ExecutorServiceCompletableTask方法(而不是submit(...))返回Future<V>
  3. 完成后,我们有可运行且可组合的期货。
  4. 实现使用替代的CompletionStage实现(注意,CompletionStage而不是CompletableFuture):

    用法:

    J8ExecutorService exec = J8Executors.newCachedThreadPool();
    CompletionStage<String> = exec
       .submit( someCallableA )
       .thenCombineAsync( exec.submit(someCallableB), (a, b) -> a + " " + b)
       .thenCombine( exec.submit(someCallableC), (ab, b) -> ab + " " + c); 
    

答案 5 :(得分:4)

建议:

http://www.thedevpiece.com/converting-old-java-future-to-completablefuture/

但是,基本上:

public class CompletablePromiseContext {
    private static final ScheduledExecutorService SERVICE = Executors.newSingleThreadScheduledExecutor();

    public static void schedule(Runnable r) {
        SERVICE.schedule(r, 1, TimeUnit.MILLISECONDS);
    }
}

而且,CompletablePromise:

public class CompletablePromise<V> extends CompletableFuture<V> {
    private Future<V> future;

    public CompletablePromise(Future<V> future) {
        this.future = future;
        CompletablePromiseContext.schedule(this::tryToComplete);
    }

    private void tryToComplete() {
        if (future.isDone()) {
            try {
                complete(future.get());
            } catch (InterruptedException e) {
                completeExceptionally(e);
            } catch (ExecutionException e) {
                completeExceptionally(e.getCause());
            }
            return;
        }

        if (future.isCancelled()) {
            cancel(true);
            return;
        }

        CompletablePromiseContext.schedule(this::tryToComplete);
    }
}

示例:

public class Main {
    public static void main(String[] args) {
        final ExecutorService service = Executors.newSingleThreadExecutor();
        final Future<String> stringFuture = service.submit(() -> "success");
        final CompletableFuture<String> completableFuture = new CompletablePromise<>(stringFuture);

        completableFuture.whenComplete((result, failure) -> {
            System.out.println(result);
        });
    }
}