2013-08-08 11 views
8

Stavo cercando di creare un tipo di dati immutabile con campi finali (incluso un array costruito e riempito prima di essere assegnato al campo membro finale) e ho notato che sembra che la JVM sia specificata per garantire che qualsiasi altro thread che ottiene un riferimento a questo oggetto vedrà i campi inizializzati e i valori dell'array (supponendo che non siano pubblicati puntatori a this all'interno del costruttore, vedere What is an "incompletely constructed object"? e How do JVM's implicit memory barriers behave when chaining constructors?).In che modo i campi finali impediscono ad altri thread di vedere oggetti parzialmente costruiti?

Sono curioso di sapere come ottenere questo risultato senza sincronizzare tutti gli accessi a questo oggetto, o altrimenti pagare una significativa penalizzazione delle prestazioni. Secondo la mia comprensione, la JVM può raggiungere questo obiettivo facendo quanto segue:

  1. Emettere un write-recinto, alla fine del costruttore
  2. Pubblicare il riferimento al nuovo oggetto solo dopo la scrittura-recinto
  3. il rilascio di un recinto di lettura ogni volta che si fa riferimento a un campo finale di un oggetto

non riesco a pensare a un modo più semplice o meno costosi di eliminare il rischio di altri thread vedere campi finali non inizializzate (o riferimenti ricorsivi attraverso campi finali).

Sembra che potrebbe imporre una severa penalizzazione delle prestazioni a causa di tutti i read-fences negli altri thread che leggono l'oggetto, ma eliminando le read-fences si introduce la possibilità che il riferimento all'oggetto venga visto in un altro processore prima di esso emette un read-fence o visualizza in altro modo gli aggiornamenti alle posizioni di memoria corrispondenti ai campi finali appena inizializzati.

Qualcuno sa come funziona? E se questo introduce una significativa penalizzazione delle prestazioni?

+0

Chiarimento relativo a una risposta cancellata: Per quanto riguarda i problemi di prestazioni che ho, non mi occupo di problemi di prestazioni algoritmiche relative a strutture di dati immutabili in generale, solo con il degrado delle prestazioni derivante dalle istruzioni di membarrier. È vero che un thread potrebbe "sapere" che una volta emesso un read-fence quando accede a un tale oggetto, non deve emettere ulteriori read-fences per quello stesso oggetto, ma non è chiaro se o come ciò sia fatto, o se c'è un altro modo per ottenere i "campi finali inizializzati", garanzia che non riesco a pensare. – jonderry

+0

capito, ecco perché l'ho cancellato. –

risposta

4

Vedere la sezione "Barriere di memoria" in this writeup.

A StoreStore barriera richiesta dopo l'impostazione dei campi finali e prima che il riferimento oggetto venga assegnato a un'altra variabile. Questa è la parte chiave delle informazioni che stai chiedendo.

In base alla sezione "Riordino", non è possibile riordinare un archivio di un campo finale rispetto a un archivio di un riferimento all'oggetto contenente il campo finale.

Inoltre, si afferma che in v.afield = 1; x.finalField = v; ... ; sharedRef = x;, nessuno dei primi due può essere riordinato rispetto al terzo; che garantisce che i negozi ai campi di un oggetto che è archiviato come un campo finale siano garantiti per essere visibili ad altri thread prima che un riferimento all'oggetto contenente il campo finale sia memorizzato.

Insieme, ciò significa che tutti i negozi ai campi finali devono essere visibili a tutti i thread prima che venga memorizzato un riferimento all'oggetto che contiene il campo.

+0

Se vuoi fare un po 'di ricerca tramite sorgente, tra l'altro, ci sono alcuni collegamenti e discussioni: l'implementazione di OpenJDK è diffusa attraverso questa email: http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/ 2012-February/007312.html - Inserisco questo messaggio non come una fonte concisa di informazioni, ma come punto di partenza per osservare alcune implementazioni su varie piattaforme. –

Problemi correlati