Java 8引入了CompletableFuture
,一个可组合的Future的新实现(包括一堆thenXxx方法)。我想独占使用它,但我想使用的许多库只返回不可组合的Future
实例。
有没有办法在Future
内包装一个返回的CompleteableFuture
个实例,以便我可以编写它?
答案 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
简而言之,这个想法如下:
CompletableTask<V>
接口 - 联合的
CompletionStage<V>
+ RunnableFuture<V>
ExecutorService
从CompletableTask
方法(而不是submit(...)
)返回Future<V>
实现使用替代的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);
});
}
}