15

Ich versuche zu verstehen, wie CompletableFuture in Java 8 interagiert mit der Java memory model. Es scheint mir, dass für Programmierer Vernunft soll die folgenden idealerweise zutreffen:CompleableFuture, veränderbare Objekte und Speicher Sichtbarkeit

  1. Aktionen in dem Thread,
  2. ein CompletableFuture geschehen zuvor all Fertig abhängige Stufen vervollständigt
  3. Aktionen im Thread ausgeführt werden, dass ein Beendigungsregister schafft eine abhängige Stufe passieren-before die Beendigung abhängige Stufe ausgeführt

Es gibt eine Notiz in java.util.concurrent documentation, dass zu sagen:

Aktionen in einem Thread vor der Vorlage eines Runnable zu einem Executorgeschehen zuvor seine Ausführung beginnt. Ähnlich für Callable s an eine ExecutorService eingereicht.

, die darauf hindeuten würden, dass die erste Eigenschaft wahr, solange der Thread, der die Zukunft vervollständigt die Abschluss abhängig führt Bühne oder legt sie auf ein Executor. Auf der anderen Seite, nach CompletableFuture documentation Lese bin ich nicht so sicher, dass:

Aktionen für abhängige Beendigungen von Nicht-Asynchron-Verfahren geliefert wird, können von dem Thread ausgeführt werden, der die aktuellen CompletableFuture, oder von einem anderen Anrufer abgeschlossen einer Abschlussmethode.

Was mich auf meine Fragen bringt:

  1. Sind die beiden hypothetischen Eigenschaften oben wahr ist oder nicht?
  2. Gibt es irgendeine spezifische Dokumentation über das Vorhandensein oder Fehlen von Speicher Sichtbarkeit garantiert, wenn Sie mit CompletableFuture arbeiten?

Nachtrag:

Auf dem Weg von einem konkreten Beispiel, betrachten Sie diesen Code:

List<String> list1 = new ArrayList<>(); 
list1.add("foo"); 

CompletableFuture<List<String>> future = 
     CompletableFuture.supplyAsync(() -> { 
      List<String> list2 = new ArrayList<>(); 
      list2.addAll(list1); 
      return list2; 
     }); 

ist sichergestellt, dass "foo"-list1 Zugabe zu der Lambda-Funktion sichtbar ist ? Ist gewährleistet, dass das Hinzufügen von list1 zu list2 für die abhängigen Stufen von future sichtbar ist?

+1

Können Sie erklären, was Sie mit „Thread, der einen Abschluss Register“ bedeuten – Misha

+1

@Misha: die OP bedeutet natürlich eine * Abschluss Aktion * oder eine abhängige Stufe. – Holger

+1

@Holger wenn er Abschluss Aktion bedeutet, dann sind die beiden Fragen gleich. Es ist plausibler, dass er abhängiges Stadium meint. – Misha

Antwort

3
  1. Ja, beide Hypothesen sind wahr. Der Grund ist, dass alle *Async() Methoden in CompletableFuture eine java.util.concurrent.Executor verwenden, um den asynchronen Aufruf durchzuführen.Wenn Sie keinen angeben, ist dies entweder common pool oder ein Executor, der für jede Aufgabe einen new thread erstellt (falls Sie die Größe des gemeinsamen Pools auf 0 oder 1 beschränken) oder einen vom Benutzer bereitgestellten Executor. Wie Sie bereits herausgefunden, die documentation der Executor sagt:

    Aktionen in einem Thread vor einem lauffähiges Objekt zu einem Executor passieren-vor der Ausführung beginnt, vielleicht in einem anderen Thread zu senden.

    So in Ihrem Beispiel ist gewährleistet, dass "foo" Teil list1 in Ihrem Lambda ist und dass list2 ist sichtbar in der nachfolgenden Stufen.

  2. Dies wird im Wesentlichen von der Dokumentation Executor abgedeckt.

+0

Danke für Ihre Antwort! Ich bemühe mich zu verstehen, dass zum Beispiel in Bezug auf 2, wenn der Thread, der die Zukunft vervollständigt, sich von dem Thread unterscheidet, der die abhängige Stufe erstellt, was die _happens-before-Beziehung zwischen Aktionen in dem Thread festlegt, der die abhängige Stufe erstellt und die Ausführung der abhängigen Stufe? Würde die durch "Executor" garantierte Beziehung "happens-before" nur die Beziehung zwischen Aktionen im Thread, der die Zukunft vervollständigt, und der Ausführung der abhängigen Phase garantieren? –

+0

@AapoLaitinen Die Übergabe zwischen zwei Threads wird immer durch einen 'Executor' gehen. Es gibt also definitionsgemäß eine * happen-before * -Beziehung. Die Zukunft zu vervollständigen hat die Semantik von 'Future # get()', die auch eine * happen-before * -Verbindung herstellt. –

Verwandte Themen