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?

Antworten auf die Frage(2)

Ihre Antwort auf die Frage