Wie verhindern letzte Felder, dass andere Threads teilweise konstruierte Objekte sehen?

8

Ich habe versucht, einen unveränderlichen Datentyp zu erstellen, der endgültige Felder enthält (einschließlich eines Arrays, das vor dem Zuordnen zu dem letzten Elementfeld erstellt und gefüllt wird) und bemerkte, dass die JVM so spezifiziert ist, dass sie alle anderen garantiert Thread, der eine Referenz auf dieses Objekt erhält, sieht die initialisierten Felder und Array-Werte (vorausgesetzt, dass keine Zeiger auf this im Konstruktor veröffentlicht sind, siehe Was ist ein" unvollständig konstruiertes Objekt "? und Wie verhalten sich JVMs implizite Speicherbarrieren beim Verketten von Konstruktoren? ).

Ich bin gespannt, wie dies erreicht wird, ohne jeden Zugriff auf dieses Objekt zu synchronisieren oder anderweitig eine erhebliche Leistungseinbuße zu zahlen. Nach meinem Verständnis kann die JVM dies erreichen, indem sie Folgendes tut:

  1. Geben Sie am Ende des Konstruktors einen Schreib-Fence aus
  2. Veröffentlichen Sie den Verweis auf das neue Objekt erst nach dem Schreib-Fence
  3. Geben Sie immer dann einen Lesezaun aus, wenn Sie auf ein letztes Feld eines Objekts verweisen

Ich kann mir keinen einfacheren oder billigeren Weg vorstellen, das Risiko zu eliminieren, dass andere Threads nicht initialisierte Endfelder (oder rekursive Referenzen durch Endfelder) sehen.

Es scheint, als könnte es aufgrund der Lesezäune in den anderen Threads, die das Objekt lesen, eine schwerwiegende Leistungseinbuße auferlegen, aber das Eliminieren der Lesezäune führt die Möglichkeit ein, dass die Objektreferenz in einem anderen Prozessor erkannt wird, bevor sie ausgegeben wird ein Lesezaun oder sieht anderweitig die Aktualisierungen der Speicherstellen, die den neu initialisierten Endfeldern entsprechen.

Weiß jemand, wie das funktioniert? Und ob dies zu einer erheblichen Leistungseinbuße führt?

    
jonderry 08.08.2013, 01:09
quelle

1 Antwort

4

Siehe den Abschnitt "Speicherbarrieren" in dieser Beschreibung .

Eine StoreStore Barriere wird benötigt, nachdem die endgültigen Felder festgelegt wurden und bevor die Objektreferenz einer anderen Variablen zugewiesen wird. Dies ist der Schlüssel zu Informationen, über die Sie nachfragen.

Gemäß dem Abschnitt "Neuordnung" kann ein Speicher eines letzten Feldes nicht in Bezug auf einen Speicher einer Referenz zu dem Objekt, das das letzte Feld enthält, neu geordnet werden.

Zusätzlich gibt es an, dass in v.afield = 1; x.finalField = v; ... ; sharedRef = x; keiner der ersten beiden in Bezug auf den dritten umgeordnet werden kann; Dies stellt sicher, dass Speicher für die Felder eines Objekts, das als letztes Feld gespeichert wird, garantiert für andere Threads sichtbar sind, bevor ein Verweis auf das Objekt gespeichert wird, das das letzte Feld enthält.

Zusammen bedeutet dies, dass alle Stores für die endgültigen Felder für alle Threads sichtbar sein müssen, bevor ein Verweis auf das Objekt mit dem Feld gespeichert wird.

    
Jason C 08.08.2013, 03:38
quelle

Tags und Links