将 Java Future 转换为 CompletableFuture
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23301598/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Transform Java Future into a CompletableFuture
提问by Dan Midwood
Java 8 introduces CompletableFuture
, a new implementation of Future that is composable (includes a bunch of thenXxx methods). I'd like to use this exclusively, but many of the libraries I want to use return only non-composable Future
instances.
Java 8 引入CompletableFuture
了一个新的 Future 实现,它是可组合的(包括一堆 thenXxx 方法)。我想专门使用它,但我想使用的许多库只返回不可组合的Future
实例。
Is there a way to wrap up a returned Future
instances inside of a CompleteableFuture
so that I can compose it?
有没有办法将返回的Future
实例包装在 a 中,CompleteableFuture
以便我可以编写它?
采纳答案by nosid
There is a way, but you won't like it. The following method transforms a Future<T>
into a CompletableFuture<T>
:
有一种方法,但你不会喜欢它。以下方法将 aFuture<T>
转换为 a CompletableFuture<T>
:
public static <T> CompletableFuture<T> makeCompletableFuture(Future<T> future) {
if (future.isDone())
return transformDoneFuture(future);
return CompletableFuture.supplyAsync(() -> {
try {
if (!future.isDone())
awaitFutureIsDoneInForkJoinPool(future);
return future.get();
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
// Normally, this should never happen inside ForkJoinPool
Thread.currentThread().interrupt();
// Add the following statement if the future doesn't have side effects
// future.cancel(true);
throw new RuntimeException(e);
}
});
}
private static <T> CompletableFuture<T> transformDoneFuture(Future<T> future) {
CompletableFuture<T> cf = new CompletableFuture<>();
T result;
try {
result = future.get();
} catch (Throwable ex) {
cf.completeExceptionally(ex);
return cf;
}
cf.complete(result);
return cf;
}
private static void awaitFutureIsDoneInForkJoinPool(Future<?> future)
throws InterruptedException {
ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker() {
@Override public boolean block() throws InterruptedException {
try {
future.get();
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
return true;
}
@Override public boolean isReleasable() {
return future.isDone();
}
});
}
Obviously, the problem with this approach is, that for each Future, a thread will be blocked to wait for the result of the Future--contradicting the idea of futures. In some cases, it might be possible to do better. However, in general, there is no solution without actively wait for the result of the Future.
显然,这种方法的问题在于,对于每个Future,都会阻塞一个线程以等待Future的结果——这与Futures 的想法相矛盾。在某些情况下,可能会做得更好。但是,一般情况下,不积极等待Future的结果是没有解决方案的。
回答by Kafkaesque
If the library you want to use also offers a callback style method in addition to the Future style, you can provide it a handler that completes the CompletableFuture without any extra thread blocking. Like so:
如果你想使用的库除了 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(...)
Without the callback the only other way I see solving this is to use a polling loop that puts all your Future.isDone()
checks on a single thread and then invoking complete whenever a Future is gettable.
如果没有回调,我认为解决此问题的唯一另一种方法是使用轮询循环,将所有Future.isDone()
检查放在单个线程上,然后在可获取 Future 时调用 complete。
回答by Valery Silaev
Let me suggest another (hopefully, better) option: https://github.com/vsilaev/java-async-await/tree/master/com.farata.lang.async.examples/src/main/java/com/farata/concurrent
让我建议另一个(希望更好)选项:https: //github.com/vsilaev/java-async-await/tree/master/com.farata.lang.async.examples/src/main/java/com/farata /同时
Briefly, the idea is the following:
简而言之,想法如下:
- Introduce
CompletableTask<V>
interface -- the union of theCompletionStage<V>
+RunnableFuture<V>
- Warp
ExecutorService
to returnCompletableTask
fromsubmit(...)
methods (instead ofFuture<V>
) - Done, we have runnable AND composable Futures.
- 介绍
CompletableTask<V>
接口——CompletionStage<V>
+的并集RunnableFuture<V>
- 扭曲
ExecutorService
以CompletableTask
从submit(...)
方法返回(而不是Future<V>
) - 完成了,我们有了可运行和可组合的 Futures。
Implementation uses an alternative CompletionStage implementation (pay attention, CompletionStagerather than CompletableFuture):
实现使用替代的 CompletionStage 实现(注意,CompletionStage而不是 CompletableFuture):
Usage:
用法:
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);
回答by Dmitry Spikhalskiy
I published a little futurityproject that tries to make better than the straightforward wayin the answer.
The main idea is to use the only one thread (and of course with not just a spin loop) to check all Futures states inside, which helps to avoid blocking a thread from a pool for each Future -> CompletableFuture transformation.
主要思想是使用唯一的一个线程(当然不仅仅是一个自旋循环)来检查内部的所有 Futures 状态,这有助于避免为每个 Future -> CompletableFuture 转换阻塞池中的线程。
Usage example:
用法示例:
Future oldFuture = ...;
CompletableFuture profit = Futurity.shift(oldFuture);
回答by Gabriel Francisco
Suggestion:
建议:
http://www.thedevpiece.com/converting-old-java-future-to-completablefuture/
http://www.thedevpiece.com/converting-old-java-future-to-completablefuture/
But, basically:
但是,基本上:
public class CompletablePromiseContext {
private static final ScheduledExecutorService SERVICE = Executors.newSingleThreadScheduledExecutor();
public static void schedule(Runnable r) {
SERVICE.schedule(r, 1, TimeUnit.MILLISECONDS);
}
}
And, the CompletablePromise:
并且,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);
}
}
Example:
例子:
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);
});
}
}
回答by Matthieu
If your Future
is the result of a call to an ExecutorService
method (e.g. submit()
), the easiest would be to use the CompletableFuture.runAsync(Runnable, Executor)
method instead.
如果您Future
是调用ExecutorService
方法(例如submit()
)的结果,最简单的CompletableFuture.runAsync(Runnable, Executor)
方法是改用该方法。
From
从
Runnbale myTask = ... ;
Future<?> future = myExecutor.submit(myTask);
to
到
Runnbale myTask = ... ;
CompletableFuture<?> future = CompletableFuture.runAsync(myTask, myExecutor);
The CompletableFuture
is then created "natively".
该CompletableFuture
则创建“原生地”。
EDIT: from @SamMefford's comment, if you need to use a Callable
, just call CompletableFuture.supplyAsync(Supplier, Executor)
编辑:来自@SamMefford 的评论,如果您需要使用 a Callable
,只需致电CompletableFuture.supplyAsync(Supplier, Executor)