8

In JDK 1.6, Doug Lea utilizza final precedendo il campo next.Diversa voce `next` di ConcurrentHashMap in JDK 1.6 e JDK 1.7

static final class HashEntry<K,V> { 
    final K key; 
    final int hash; 
    volatile V value; 
    final HashEntry<K,V> next; 

Mentre in JDK 1.7, il campo next è preceduta da volatile. Inoltre noto che in JDK 1.7 il metodo get adotta il metodo getObjectVolatile per leggere il campo value, che ha la semantica del carico volatile.

Non ho senso perché Doug Lea utilizzi in precedenza final. Se ci sono problemi di correttezza, come potrebbe sostituirlo con volatile in JDK 1.7 (anche JDK 1.8)?

Edit:

In particolare, la mia domanda è che potremmo sostituire final con volatile nell'attuazione JDK 1.6 di?

+1

Questa classe non è in CHM in Java 8. – assylias

+1

OK, se questa è la tua domanda, allora no, non puoi. Il motivo per cui il modificatore è stato modificato è che l'implementazione è stata completamente cambiata. Questo non è un cambiamento isolato. – RealSkeptic

+1

@RealSkeptic, potresti presentare alcuni dettagli o articoli per la spiegazione? Grazie. –

risposta

2

Per la vostra prima domanda:

Non ho il senso per cui Doug Lea utilizza in precedenza finale. Se ci sono problemi con correttezza, allora come potrebbe sostituirlo con volatile in JDK 1.7 (anche JDK 1.8)?

Non era una questione di correttezza. Entrambe le implementazioni sono corrette in termini di sicurezza del thread. Quello che stava cercando di essere risolto era ridurre l'impronta iniziale del CHM. In Java 6, la finale di campo next richiedeva la creazione dell'oggetto con almeno un segnaposto. Ciò ha causato un'eccessiva creazione di oggetti vuoti e quindi è stato modificato per offrire semantica di creazione quando necessario.

In particolare, la mia domanda è che si possa sostituire il finale con volatili nell'attuazione JDK 1.6 di?

Certamente fino a quando le operazioni continuano ad essere coerentemente sequenziali, quali sono.


Uno dei commenti tocchi di Doug Lea su questa modifica di progettazione

/* 
* ... 
* Historical note: The previous version of this class relied 
* heavily on "final" fields, which avoided some volatile reads at 
* the expense of a large initial footprint. Some remnants of 
* that design (including forced construction of segment 0) exist 
* to ensure serialization compatibility. 
*/ 

Quindi, per rispondere a un'altra domanda si sono probabilmente avendo, perché è stato scelto inizialmente final? Per prevenire alcune letture volatili in seguito.

+0

Ho la stessa idea, ma non posso confermarlo da solo. Mi chiedo se ti vengono in mente domande simili sulle API Java, come gestirle? Grazie. –

0

Non si tratta di sostituire final con volatile. Come RealSkeptic è stato cambiato tra molti altri metodi. Lo scopo potrebbe essere l'ottimizzazione di ConcurrentHashMap.remove(). In JDK1.6 l'elenco che memorizza il bucket (oggetti raggruppati per hashcode) è CopyOnWrite così all'interno della parte remove() viene copiata, in JDK1.7 solo il puntatore next viene modificato.