Angenommen, ich habe ein Feld, auf das gleichzeitig zugegriffen wird und das viele Male gelesen und selten beschrieben wird.
public Object myRef = new Object();
Angenommen, ein Thread T1 setzt myRef einmal pro Minute auf einen anderen Wert, während N andere Threads myRef milliardenfach kontinuierlich und gleichzeitig lesen. Ich brauche nur, dass myRef irgendwann für alle Threads sichtbar ist.
Eine einfache Lösung wäre die Verwendung einer AtomicReference oder einfach so flüchtig:
public volatile Object myRef = new Object();
Afaik volatile Reads verursachen jedoch Leistungskosten. Ich weiß, dass es winzig ist, das ist eher etwas, das ich mich wundere, als etwas, das ich tatsächlich brauche. Lassen Sie uns also nicht mit der Leistung befasst sein und davon ausgehen, dass dies eine rein theoretische Frage ist.
Die Frage lautet also : Gibt es eine Möglichkeit, flüchtige Lesevorgänge für Referenzen, auf die nur selten geschrieben wird, sicher zu umgehen, indem Sie etwas an der Schreibstelle tun?
Nach einigem Lesen sieht es so aus, als könnten Speicherbarrieren das sein, was ich brauche. Wenn also ein solches Konstrukt existieren würde, wäre mein Problem gelöst:
- Schreiben
- Barriere aufrufen (synchronisieren)
- Alles wird synchronisiert und alle Threads sehen den neuen Wert. (Ohne dauerhafte Kosten an Leseseiten kann es veraltet sein oder einmalige Kosten verursachen, wenn die Caches synchronisiert werden, aber danach wird alles wieder zum regulären Feld zurückgeführt, bis zum nächsten Schreiben).
Gibt es ein solches Konstrukt in Java oder allgemein? An diesem Punkt kann ich nicht anders, als zu denken, wenn so etwas existiert hätte, wäre es bereits von den viel klügeren Leuten, die diese pflegen, in die Atompakete aufgenommen worden. (Überproportional häufiges Lesen und Schreiben war möglicherweise kein Grund zur Sorge?) Vielleicht stimmt etwas in meinem Denken nicht und ein solches Konstrukt ist überhaupt nicht möglich?
Ich habe gesehen, dass einige Codebeispiele 'volatile' für einen ähnlichen Zweck verwenden und den Vertrag vor dem Vertrag ausnutzen. Es gibt ein separates Synchronisierungsfeld, z. B.:
public Object myRef = new Object();
public volatile int sync = 0;
und beim Schreiben von Thread / Site:
myRef = new Object();
sync += 1 //volatile write to emulate barrier
Ich bin nicht sicher, ob dies funktioniert, und einige argumentieren, dass dies nur auf der x86-Architektur funktioniert. Nach dem Lesen verwandter Abschnitte in JMS funktioniert es meiner Meinung nach nur dann garantiert, wenn dieses flüchtige Schreiben mit einem flüchtigen Lesen der Threads gekoppelt ist, die den neuen Wert von myRef sehen müssen. (So wird das flüchtige Lesen nicht los).
Zurück zu meiner ursprünglichen Frage; ist das überhaupt möglich? Ist es in Java möglich? Ist es in einer der neuen APIs in Java 9 VarHandles möglich?
sync += 1;
und Ihre Reader-Threads den sync
Wert lesen , auch das myRef
Update angezeigt wird. Da Sie nur die Leser müssen das Update sehen schließlich , können Sie dies zu Ihrem Vorteil nur lesen Sync auf jedem 1000. Iteration des Lesers Thread oder etwas ähnliches verwenden. Aber Sie können auch einen ähnlichen Trick machen volatile
- zwischenspeichern Sie einfach das myRef
Feld in den Readern für 1000 Iterationen und lesen Sie es dann erneut mit volatile ...
sync
Feld gemeint haben , nein, Leser würden das sync
Feld nicht bei jeder Iteration berühren , sie würden es opportunistisch tun, wenn sie überprüfen möchten, ob es ein Update gegeben hat. Das heißt, eine einfachere Lösung wäre, die myRef
für 1000 Runden zwischenzuspeichern und dann erneut zu lesen ...