Trasforma Java Future in CompletableFuture

Java 8 introduce CompletableFuture , una nuova implementazione di Future che è componibile (include una serie di metodi thenXxx). Mi piacerebbe usarlo esclusivamente, ma molte delle librerie che voglio usare restituiscono solo istanze Future non componibili.

C’è un modo per racchiudere istanze di Future restituite all’interno di un CompleteableFuture modo che io possa comporlo?

C’è un modo, ma non ti piacerà. Il seguente metodo trasforma un Future in un CompletableFuture :

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

Ovviamente, il problema con questo approccio è che per ogni futuro , una discussione sarà bloccata per attendere il risultato del futuro, senza contraddire l’idea dei futures. In alcuni casi, potrebbe essere ansible fare di meglio. Tuttavia, in generale, non c’è soluzione senza attendere triggersmente il risultato del futuro .

Se la libreria che desideri utilizzare offre anche un metodo di stile callback oltre allo stile Future, puoi fornirgli un gestore che completa CompletableFuture senza alcun blocco aggiuntivo del thread. Così:

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

Senza la richiamata, l’unico altro modo in cui vedo risolvere questo è usare un ciclo di polling che mette tutti i tuoi controlli Future.isDone() su un singolo thread e poi invocare il completamento ogni volta che un Future è disponibile.

Ho pubblicato un piccolo progetto di futurity che cerca di migliorare il modo semplice nella risposta.

L’idea principale è quella di utilizzare l’unico thread (e ovviamente non solo un ciclo di spin) per controllare tutti gli stati Futures all’interno, il che aiuta a evitare il blocco di un thread da un pool per ogni Future -> Trasformazione CompletableFuture.

Esempio di utilizzo:

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

Lasciatemi suggerire un’altra opzione (si spera, meglio): https://github.com/vsilaev/java-async-await/tree/master/com.farata.lang.async.examples/src/main/java/com/farata / concomitante

In breve, l’idea è la seguente:

  1. Introduci l’interfaccia CompletableTask – l’unione di CompletionStage + RunnableFuture
  2. Warp ExecutorService per restituire CompletableTask dai metodi submit(...) (invece di Future )
  3. Fatto, abbiamo Futures eseguibili e componibili.

L’implementazione utilizza un’implementazione di CompletionStage alternativa (prestare attenzione, CompletionStage anziché CompletableFuture):

Uso:

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

Suggerimento:

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

Ma fondamentalmente:

 public class CompletablePromiseContext { private static final ScheduledExecutorService SERVICE = Executors.newSingleThreadScheduledExecutor(); public static void schedule(Runnable r) { SERVICE.schedule(r, 1, TimeUnit.MILLISECONDS); } } 

E, il CompletablePromise:

 public class CompletablePromise extends CompletableFuture { private Future future; public CompletablePromise(Future 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); } } 

Esempio:

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