Java 8では、構成可能なFutureの新しい実装であるCompletableFuture
が導入されています(thenXxxメソッドの束が含まれています)。これを排他的に使用したいのですが、使用したいライブラリの多くは、構成不可能なFuture
インスタンスのみを返します。
返されるFuture
インスタンスをCompleteableFuture
内にラップして、構成できるようにする方法はありますか?
方法はありますが、気に入らないでしょう。次のメソッドは、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-futuresのアイデアと矛盾する結果を待つことです。場合によっては、もっとうまくやることができるかもしれません。ただし、一般的に、Futureの結果を積極的に待たなければ解決策はありません。
使用するライブラリが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がgettableになるたびにcompleteを呼び出すポーリングループを使用することです。
別の(できればもっと良い)オプションを提案させてください: 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
をワープしてsubmit(...)
メソッドからCompletableTask
を返します(_Future<V>
_の代わりに)実装では、代替CompletionStage実装を使用します(注意を払ってください。CompletableFutureではなく、 CompletionStage )。
使用法:
_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);
_
提案:
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);
});
}
}