2016-06-20 6 views
5

So habe ich eine Methode, die eine CompletableFuture zurückgibt. Vor der Rückkehr fügt diese Methode einen Block mit thenAccept hinzu, der ausgeführt wird, nachdem die CompletableFuture abgeschlossen ist.In welcher Reihenfolge werden mehrere ThenAckgle-Blöcke einer CompleableFuture ausgeführt

Der Aufrufer dieser Methode fügt auch einen weiteren Block mit 10 hinzu. Offensichtlich kann dies mit mehreren verketteten Anrufen fortgesetzt werden.

In welcher Reihenfolge werden die CompletionStage von den thenAccept aufgerufenen Invokationen ausgeführt? Ist es garantiert die Reihenfolge, in der sie hinzugefügt werden? Wenn nicht, wie kann man garantieren, dass sie in der Reihenfolge ausgeführt werden, in der sie hinzugefügt werden?

PS: ich dies basierend bin gefragt auf meiner eigenen Erfahrung mit CompletableFuture und diese article

+2

"thenAccept" bedeutet, dass zuerst "this" CompleableFuture abgeschlossen ist und erst dann die Parameterfunktion ausgeführt wird. –

Antwort

6

Sie sind die Modellierung der Abhängigkeiten der Vollendungsstufe von ihnen verketten. Wenn Sie die Kette zwei Aktionen A und B zu einer anderen Aktion C definieren Sie die Beziehungen A → C und B → C, aber keine Beziehung zwischen A und B und daher gibt es keine Beziehung, einschließlich keine Ordnungsbeziehung zwischen ihnen, mit anderen Worten, können Sie ‚t annehmen sogar, dass einer nach dem anderen ausgeführt wird, das heißt

CompletableFuture<String> base=CompletableFuture.supplyAsync(() -> { 
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2)); 
    return "source"; 
}); 
base.thenAccept(s -> { 
    System.out.println("entered first consumer in "+Thread.currentThread()); 
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1)); 
    System.out.println("leaving first consumer"); 
}); 
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2)); 
base.thenAccept(s -> { 
    System.out.println("entered second consumer in "+Thread.currentThread()); 
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1)); 
    System.out.println("leaving second consumer"); 
}); 

wird sehr wahrscheinlich Druck etwas wie

entered first consumer in Thread[ForkJoinPool.commonPool-worker-1,5,main] 
entered second consumer in Thread[main,5,main] 
leaving second consumer 
leaving first consumer 

Obwohl, natürlich, es gibt keine Garantie darüber.


Um Ihre Abhängigkeit zwischen den beiden Verbrauchern zu erzwingen, müssen Sie sie entsprechend ketten, z.

CompletableFuture<String> base=CompletableFuture.supplyAsync(() -> { 
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2)); 
    return "source"; 
}); 
CompletableFuture<Void> next = base.thenAccept(s -> { 
    System.out.println("entered first consumer in "+Thread.currentThread()); 
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1)); 
    System.out.println("leaving first consumer"); 
}); 
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2)); 
base.thenAcceptBoth(next, (s,ignored) -> { 
    System.out.println("entered second consumer in "+Thread.currentThread()); 
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1)); 
    System.out.println("leaving second consumer"); 
}).join(); 

Hier wird der zweite Verbraucher base gekettet und next, das Ergebnis von base, erhält aber hängt von next ‚s Abschluss (die Sie normalerweise nicht erforderlich, wenn es kein Ergebnis zu vielleicht passieren Sie möchten Ihr Design überdenken, wenn Sie ein solches Szenario haben).

Alternativ können Sie die ersten Consumer zu einem Function wandeln, die durch den Wert geht, so können Sie die Kette es über thenApply, zu ermöglichen, eine andere thenAccept Bühne dafür Verkettungs.

Verwandte Themen