Die billigste Art der Etablierung geschieht davor mit einem nicht finalen Feld
Viele Fragen / Antworten haben ergeben, dass, wenn ein Klassenobjekt eine hatfinal
Wenn während der Erstellung kein Verweis auf ein Feld vorhanden ist, wird allen Threads der in das Feld geschriebene Wert garantiert angezeigt, sobald der Konstruktor abgeschlossen ist. Sie haben auch angegeben, dass die Speicherung in einemfinal
field Ein Verweis auf ein veränderbares Objekt, auf das keine externen Threads zugegriffen haben, stellt sicher, dass alle vor dem Speichern vorgenommenen Mutationen auf allen Threads sichtbar sind, die über das Feld auf das Objekt zugreifen. Leider gilt keine Garantie für Schreiben von nichtfinal
Felder.
Eine Frage, die ich nicht beantwortet sehe, ist: Wenn die Semantik einer Klasse so ist, dass ein Feld nicht sein kannfinal
, aber man möchte die "Veröffentlichung" des Feldes und des damit identifizierten Objektes sicherstellen, wie geht das am effizientesten? Als Beispiel betrachten
class ShareableDataHolder<T>
{
Object data; // Always identifies either a T or a SharedDataHolder<T>
}
private class SharedDataHolder<T> extends ShareableDataHolder<T>
{
Object data; // Always identifies either a T or a lower-numbered SharedDataHolder<T>
final long seq; // Immutable; necessarily unique
}
Die Absicht wäre dasdata
wird anfänglich ein Datenobjekt direkt identifizieren, aber dass es jederzeit legitimerweise geändert werden kann, um ein zu identifizierenSharedDataHolder<T>
die direkt oder indirekt ein äquivalentes Datenobjekt kapselt. Angenommen, der gesamte Code ist so geschrieben, dass er korrekt funktioniert (wenn auch nicht unbedingt optimal effizient), wenn er gelesen wirddata
kann willkürlich jeden Wert zurückgeben, in den jemals geschrieben wurdedata
, kann aber fehlschlagen, wenn es liestnull
.
Deklarierenvolatile Object data
wäre semantisch korrekt, würde aber wahrscheinlich zusätzliche Kosten für jeden nachfolgenden Zugriff auf das Feld verursachen. Das Eingeben einer Dummy-Sperre nach dem erstmaligen Setzen des Feldes würde funktionieren, wäre aber unnötig langsam. Einen Dummy habenfinal
Feld, das das Objekt selbst identifiziert, scheint zu funktionieren; Obwohl ich technisch denke, dass alle Zugriffe auf das andere Feld über das andere Feld erfolgen müssen, sehe ich kein realistisches Szenario, in dem dies von Bedeutung wäre. In jedem Fall erscheint es verschwenderisch, ein Dummy-Feld zu haben, dessen Zweck nur darin besteht, die entsprechende Synchronisation über seine Existenz bereitzustellen.
Gibt es eine saubere Möglichkeit, den Compiler darüber zu informieren, dass ein bestimmter Schreibzugriff erfolgtdata
innerhalb des Konstruktors sollte eine Vor-ereignis-Beziehung in Bezug auf alle Lesevorgänge dieses Felds bestehen, die auftreten, nachdem der Konstruktor zurückgegeben wurde (wie es der Fall wäre, wenn das Feld vorhanden wäre)final
), ohne die damit verbundenen Kosten zu tragenvolatile
, Schlösser usw.? Alternativ, wenn ein Thread gelesen werden solldata
und finde es null, könnte es irgendwie das Lesen in einer solchen Weise wiederholen, um ein "Nachher" in Bezug auf das Schreiben von zu etablierendata
[zu erkennen, dass eine solche Anfrage langsam sein kann, aber nicht sehr oft erfolgen muss]?
PS: Wenn Vorgänge vor Beziehungen nicht transitiv sind, besteht im folgenden Szenario eine ordnungsgemäße Vorgänge-vor-Beziehung?
Thread 1 schreibt in ein nicht endgültiges Felddat
in einem ObjektFred
und speichert einen Verweis darauf in einem abschließenden FeldGeorge
.Thread 2 kopiert die Referenz vonGeorge
in ein nicht endgültiges FeldLarry
.Thread 3 liestLarry.dat
.Soweit ich weiß, besteht eine Beziehung zwischen dem Schreiben von Freds Feld, bevor es passiertdat
und eine Lektüre vonGeorge
. Wäre zwischen dem Schreiben von Freds eine Beziehung zustande gekommen?dat
und eine Lektüre vonLarry
das gibt einen Verweis auf Fred zurück, der von einem kopiert wurdefinal
Bezug aufFred
? Wenn nicht, gibt es eine "sichere" Möglichkeit, eine in a enthaltene Referenz zu kopierenfinal
Feld zu einem nicht endgültigen Feld, auf das über andere Threads zugegriffen werden kann?
PPS - Wenn auf ein Objekt und seine Bestandteile erst nach Abschluss des Hauptkonstruktors außerhalb des Erstellungs-Threads zugegriffen wird und der letzte Schritt des Hauptkonstruktors darin besteht, sie im Hauptobjekt zu speichern. Afinal
Verweis auf sich selbst, gibt es eine "plausible" Implementierung / ein "plausibles" Szenario, in dem ein anderer Thread ein teilweise konstruiertes Objekt sehen könnte, unabhängig davon, ob dies tatsächlich von irgendetwas verwendet wird oder nichtfinal
Referenz?