15

Sto cercando di capire come CompletableFuture in Java 8 interagisce con Java memory model. Mi sembra che per il programmatore di sanità mentale, il seguente dovrebbe idealmente tenere vero:CompletaFuturo, oggetti mutevoli e visibilità della memoria

  1. azioni nel thread che completa un CompletableFuturecapitare-prima eventuali completamenti fasi dipendenti vengono eseguiti
  2. azioni nel thread che registra un completamento crea una fase dipendente accade-prima viene eseguito il completamento fase dipendente

C'è una nota in java.util.concurrent documentation dicendo che:

azioni a un filo prima della presentazione di una Runnable ad un Executoraccadere-prima dell'inizio sua esecuzione. Allo stesso modo per Callable s inviato a un ExecutorService.

che suggerisce che la prima proprietà è vero, fino a quando il filo che completa il futuro esegue il completamento fase dipendente o lo sottopone a un Executor. D'altra parte, dopo aver letto CompletableFuture documentation io non sono così sicuro di questo:

azioni forniti per completamenti dipendenti di metodi non asincrone possono essere eseguite dal thread che completa l'attuale CompletableFuture, o da qualsiasi altra chiamante di un metodo di completamento.

che mi porta alle mie domande:

  1. sono le due proprietà sopra ipotetici vero o no?
  2. C'è qualche documentazione specifica ovunque sulla presenza o sulla mancanza di garanzie di visibilità della memoria quando si lavora con CompletableFuture?

Addendum:

Nel modo di un esempio concreto, si consideri questo codice:

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

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

E 'garantito che l'aggiunta di "foo"-list1 è visibile alla funzione lambda ? È garantito che l'aggiunta di list1 a list2 sia visibile alle fasi dipendenti di future?

+1

può chiarire cosa si intende per "filo che registra un completamento" – Misha

+1

@Misha: OP significa ovviamente * * completamento azione o di una fase dipendenti. – Holger

+1

@Holger se intende un'azione di completamento, quindi le due domande sono le stesse. È più plausibile che lui voglia dire stadio dipendente. – Misha

risposta

3
  1. Sì, entrambe le ipotesi sono vere. Il motivo è che tutti i metodi *Async() in CompletableFuture utilizzeranno un java.util.concurrent.Executor per effettuare la chiamata asincrona.Se non ne viene fornito uno, sarà lo common pool o un Executor che crea un new thread per ciascuna attività (nel caso in cui si limiti la dimensione del pool comune a 0 o 1) o un Executor fornito dall'utente. Come già scoperto, la documentation del Executor dice:

    azioni a un filo prima di presentare un oggetto Runnable ad un esecutore accadere-prima della sua esecuzione inizia, forse in un altro thread.

    Quindi nel tuo esempio, è garantito che "foo" fa parte della list1 nel vostro lambda e che list2 è visibile in fasi successive.

  2. Questo è fondamentalmente coperto dalla documentazione di Executor.

+0

Grazie per la tua risposta! Quello che sto cercando di capire è che, per esempio riguardo a 2, se il thread che completa il futuro è diverso dal thread che crea lo stage dipendente, cosa stabilisce la relazione _happens-before_ tra le azioni nel thread che crea lo stage dipendente e l'esecuzione della fase dipendente? Non sarebbe la relazione _happens-before_ garantita dall'Esecutore a garantire solo la relazione tra le azioni nel thread che completa il futuro e l'esecuzione dello stadio dipendente? –

+0

@AapoLaitinen Il passaggio tra due thread passerà sempre attraverso un 'Executor'. Quindi esiste per definizione una relazione * happen-before *. Completing the Future ha la semantica di 'Future # get()' che stabilisce anche una relazione * happen-before *. –

Problemi correlati