2016-04-06 4 views
1

Im folgenden Code macht es keinen Unterschied, ob Sie thenRunAsync anrufen? Sollte ich nur anrufen thenRun stattdessen?Macht thenRunAsync (im Gegensatz zu thenRun) einen Unterschied, wenn es nach einem runAsync-Aufruf verkettet wird?

CompletableFuture.runAsync(this::doWork , executorService) 
    .thenRunAsync(this::handleSuccess); 

Ausarbeiten als Reaktion auf die Kommentare: Wenn ich stattdessen diesen Code verwenden waren,

CompletableFuture.runAsync(this::doWork , executorService) 
    .thenRun(this::handleSuccess); 

wäre es anders verhalten?

In beiden Fällen ist das Verhalten nicht blockierend, und die zweite Aufgabe wird nicht ausgeführt, bis die erste abgeschlossen ist, soweit ich es verstehe, jedenfalls.

+0

Nun ist der Unterschied, dass "handleSuccess" asynchron aufgerufen wird, wenn "doWork" normal beendet wurde. Ich bin mir nicht sicher, welche Art von Antwort du suchst. – Tunaki

+0

@Tunaki: Ich nehme an, die Frage zielt darauf ab, dass die an 'thenRun' übergebene Aktion auch asynchron ausgeführt wird (in Bezug auf den Thread, der' thenRun' aufruft), wenn die vorherige Stufe nicht bis zum Ende abgeschlossen ist der 'thenRun'-Aufruf. Aber anscheinend gibt es noch mehr Unterschiede, als die Frage anstrebt ... – Holger

Antwort

4

Die Methode thenRun ermöglicht die Ausführung der Runnable direkt im Thread des Aufrufers, wenn die CompletableFuture bereits abgeschlossen ist. Da selbst in einer direkten Aufrufkette wie CompletableFuture.runAsync(…).thenRun(…); die Möglichkeit besteht, dass die asynchrone Task bereits zum Zeitpunkt thenRun aufgerufen wurde, besteht die Möglichkeit, dass die abhängige Aktion im Thread des Aufrufers ausgeführt wird, im Gegensatz zu thenRunAsync, die immer den Standard (oder zur Verfügung gestellt) Executor.

Also in einem Satz, ja, es macht einen Unterschied.


By the way, mit thenRunAsync (der einzigen Argumente Version) wird die Aktion mit den Executor wieder auf den Werks- Anruf, aber der Executor Standard geliefert nicht ausgeführt werden.

Sie können ganz einfach die verschiedenen Verhaltensweisen vergleichen:

public static void main(String[] args) { 
    ExecutorService e=Executors.newSingleThreadExecutor(r -> new Thread(r, "sole thread")); 
    CompletableFuture<?> f=CompletableFuture.runAsync(()->{}, e); 
    f.join(); 
    f.thenRun(()->System.out.println("thenRun:\t"+Thread.currentThread())); 
    f.thenRunAsync(()->System.out.println("thenRunAsync:\t"+Thread.currentThread())); 
    f.thenRunAsync(()->System.out.println("thenRunAsync+e:\t"+Thread.currentThread()), e); 
    e.shutdown(); 
} 

druckt

thenRun:  Thread[main,5,main] 
thenRunAsync: Thread[ForkJoinPool.commonPool-worker-1,5,main] 
thenRunAsync+e: Thread[sole thread,5,main] 

während

public static void main(String[] args) { 
    ExecutorService e=Executors.newSingleThreadExecutor(r -> new Thread(r, "sole thread")); 
    CompletableFuture<?>f=CompletableFuture.runAsync(()->LockSupport.parkNanos((int)1e9),e); 
    f.thenRun(()->System.out.println("thenRun:\t"+Thread.currentThread())); 
    f.thenRunAsync(()->System.out.println("thenRunAsync:\t"+Thread.currentThread())); 
    f.thenRunAsync(()->System.out.println("thenRunAsync+e:\t"+Thread.currentThread()), e); 
    LockSupport.parkNanos((int)2e9); 
    e.shutdown(); 
} 

thenRun:  Thread[sole thread,5,main] 
thenRunAsync: Thread[ForkJoinPool.commonPool-worker-1,5,main] 
thenRunAsync+e: Thread[sole thread,5,main] 
gedruckt werden

thenRun So kann thenRun die Aktion in entweder dem Thread des Aufrufers oder dem Executor Thread ausführen, während das Einzelargument thenRunAsync immer den Fork/Join-Pool verwendet und nur die beiden Argumente thenRunAsync immer den bereitgestellten Executor verwenden.

Verwandte Themen