2016-07-23 7 views
2

Ich habe eine Methode (kann gleichzeitig von verschiedenen Threads aufgerufen werden), die eine asynchrone Aufgabe erstellt und eine CompletableFuture zurückgibt. Ich mag die Zeit messen es die Aufgabe auszuführen nimmt, indem sie es mit einem whenComplete Chaining (...) wie folgt:Wie asynchrone Lambdas im Java-Bereich zu lokalen Variablen

public CompletableFuture<Result> createTask(...) { 
    CompletableFuture<Result> result = ...; 
    final long startTime = System.currentTimeMillis(); 
    result.whenComplete((res, err) -> { 
     System.out.println(System.currentTimeMillis() - startTime); 
    } 
} 

Das Lambda, das gibt es in asynchron ausgeführt werden und die Methode, die ich schrieb auch Multithreading sein. Wird dieses Lambda in der Lage sein, die genaue Zeit auszudrucken? Wie behandelt Java den Variablenbereich, wenn das Lambda asynchron von einem anderen Thread ausgeführt wird?

+0

Bitte lesen Sie Ihre Frage erneut und bearbeiten Sie sie. Die Formulierung ist nicht sehr klar. – michaelsnowden

Antwort

4

Wenn ein Lambda eine Variable erfasst, kann man sich vorstellen, dass das Lambda eine Kopie des Werts dieser Variablen erhält. Da nur finale oder effektiv endgültige Variablen erfasst werden können, ist es für Lambdas sicher, sie zu kopieren. Ihre Werte ändern sich nicht, daher besteht keine Gefahr, dass die Kopie nicht mit der ursprünglichen Variablen übereinstimmt.

Lambdas muss nicht mit anonymen Klassen implementiert werden, aber Sie können sie konzeptionell als syntaktischen Zucker für anonyme Klassen betrachten. Ihr whenComplete Anruf entspricht:

long startTime = System.currentTimeMillis(); 

result.whenComplete(new BiConsumer<T, U>() { 
    @Override public void accept(T res, U err) { 
     System.out.println(System.currentTimeMillis() - startTime); 
    } 
}); 

Die Sache ist, ist variabel Capturing mit Lambda-Ausdrücke nicht neu. Anonyme Klassen erfassen auch Variablen, und sie haben es getan, bevor lambdas kam. Was passiert, ist, dass sie heimlich Kopien von erfassten Variablen verstauen. Sie erhalten synthetische private Felder, um diese versteckten Werte zu speichern. Der obige Code ist eigentlich eher wie dieses, wenn wir das synthetische Feld explizit zu machen:

long startTime = System.currentTimeMillis(); 

result.whenComplete(new BiConsumer<T, U>() { 
    private final long _startTime = startTime; 

    @Override public void accept(T res, U err) { 
     System.out.println(System.currentTimeMillis() - _startTime); 
    } 
}); 

Beachten Sie, dass, sobald diese anonyme BiConsumer instanziiert wird es auf eigenen Füßen steht. Der Rumpf von accept() verweist jetzt auf eine Instanzvariable, nicht auf die erfasste Variable. Das anonyme Objekt ist weder mit der äußeren Funktion noch mit dem Thread verknüpft, in dem es erstellt wurde. accept() kann jederzeit und von jedem Thread aufgerufen werden und wird sich so verhalten, wie man es erwarten würde, auch wenn die ursprüngliche startTime Variable längst tot und vergraben ist.

Verwandte Themen