ConcurrentHashMap reorder-Anweisung?
Ich bin auf der Suche in ConcurrentHashMap Umsetzung und eine Sache machen, die mich verwirrt.
/* Specialized implementations of map methods */
V get(Object key, int hash) {
if (count != 0) { //read-volatile
HashEntry<K,V> e = getFirst(hash);
while (e != null) {
if (e.hash == hash && key.equals(e.key)) {
V v = e.value;
if (v != null)
return v;
return readValueUnderLock(e); //recheck
}
e = e.next;
}
}
return null;
}
und
/**
* Reads value field of an entry under lock. Called if value
* field ever appears to be null. This is possible only if a
* compiler happens to reorder a HashEntry initialization with
* its table assignment, which is legal under memory model
* but is not known to ever occur.
*/
V readValueUnderLock(HashEntry<K,V> e) {
lock();
try {
return e.value;
} finally {
unlock();
}
}
und HashEntry Konstruktor
/**
* ConcurrentHashMap list entry. Note that this is never exported
* out as a user-visible Map.Entry.
*
* Because the value field is volatile, not final, it is legal wrt
* the Java Memory Model for an unsynchronized reader to see null
* instead of initial value when read via a data race. Although a
* reordering leading to this is not likely to ever actually
* occur, the Segment.readValueUnderLock method is used as a
* backup in case a null (pre-initialized) value is ever seen in
* an unsynchronized access method.
*/
static final class HashEntry<K,V> {
final K key;
final int hash;
volatile V value;
final HashEntry<K,V> next;
HashEntry(K key, int hash, HashEntry<K,V> next, V value) {
this.key = key;
this.hash = hash;
this.next = next;
this.value = value;
}
setzen implementieren
tab[index] = new HashEntry<K,V>(key, hash, first, value);
Ich verwirrt HashEntry Kommentar, als JSR-133, einmal HashEntry aufgebaut ist, alle final-Felder werden sichtbar für alle anderen threads, Wert Feld ist flüchtig, so dass ich denke, dass es sichtbar für andere threads zu??? . Anderer Punkt, ist der reorder sagte er: HashEntry Objektreferenz zugewiesen werden kann, um die Registerkarte [...], bevor es voll ist gebaut (also Ergebnis ist in anderen threads sehen kann, dieser Eintrag, aber e.der Wert kann null sein) ?
Update:
Ich lese diese Artikel und es ist gut. Aber muss ich darum kümmern muss, einen Fall wie diesen
ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue();
thread1:
Person p=new Person("name","student");
queue.offer(new Person());
thread2:
Person p = queue.poll();
Ist es eine chance, dass Thread2 verzahnt, erhalten eine unvollendete-Konstrukt Person, Objekt, genau wie HashEntry in
Registerkarte[index] = new HashEntry(Schlüssel, hash, ersten, Wert);
?
- Mit Wert flüchtige sicherzustellen, können Sie die Sichtbarkeit von allen anderen threads.
- yep, so dass alle Felder sichtbar sind, die durch alle anderen threads, also, warum wir nur brauchen, um über den Wert von 'value', null sein?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Für Interessierte, die eine Antwort von Doug Lea auf dieses Thema, er hat vor kurzem erklärt, der Grund für
readValueUnderLock
Dies ist eine Reaktion auf jemanden, der hatte die Frage:
Antwort:
Es können alle angezeigt werden hier
Anderen threads sehen Wert als gut, aber... Die Zuweisung des Eintrags (in dem Object[]) geschieht, nachdem die Initialisierung UND unter Verschluss.
Also, wenn jeder thread sieht
null
wird es versuchen, Lesen Sie den Wert unter dem Schloss.Nein, es kann nicht b/c es ist eine flüchtige Zuordnung (
value
) und als Mittel, bei allen anderen Operationen müssen eingestellt werden, bevor die hand (d.h. nicht nachbestellt werden). Beachten Sie auch, dass java-Objekt erstellen, ist 2-phase, erstellen Sie ein leeres Objekt w/null/null-Felder (wie bei der Standard-c-tor) und dann den Aufruf<init>
- Methode (das ist der Konstruktor). Das Objekt kann nicht zugeordnet werden, was vor Abschluss der Konstruktor aufrufen und die Letzte Zuweisung vonvalue
(um sicherzugehen, dass die richtige Reihenfolge auch bekannt als passiert-vor)Soweit ich das verstehe-Speicher-Modell, schreiben volatile-variable ist garantiert, um sichtbar zu werden, indem alle nachfolgenden (definiert durch Synchronisierung, um) liest diese variable.
Aber nichts garantiert, dass das Lesen von
e.value
imget()
im Anschluss zu schreiben, dervalue
im Konstruktor (da gibt es keine synchronisiert-mit Beziehungen zwischen diesen Aktionen), so dass Speicher-Modell ermöglicht diese Art der Nachbestellung und explizite Synchronisation im Fall vonnull
Wert ist notwendig, um sicherzustellen, dass wir Lesen den richtigen Wert.UPDATE: Das neue memory-Modell garantiert, dass alle schreiben auf nicht-volatile variable vor zu schreiben, um die volatile variable gesehen werden kann, die von anderen threads nach dem anschließenden Lesen der, dass die volatile variable, aber nicht Umgekehrt.
Hier der zugehörige Auszug aus Das Java-Memory-Modell von Jeremy Manson, William Pugh und Sarita Adve:
Daher Abtretung des konstruierten Objekts neu angeordnet werden können und mit dem schreiben zu volatile-variable in einem Konstruktor, so dass der check-in-Frage erforderlich ist.
synchronized
block)