Der undurchsichtige Modus, der mit VarHandle getOpaque und setOpaque erreicht wird, fügt Einschränkungen gegenüber dem einfachen Modus hinzu, die eine minimale Kenntnis einer Variablen ermöglichen, die dem Interthread-Zugriff unterliegt, wenn alle Zugriffe den undurchsichtigen (oder stärkeren) Modus verwenden.
[...]
Release/Acquire (oder RA)-Modus wird mithilfe von VarHandle setRelease, getAcquire und verwandten Methoden erhalten und fügt dem undurchsichtigen Modus eine „kumulative“ Kausalitätsbeschränkung hinzu
Wir haben einen größtenteils Single-Threaded-, leistungskritischen Codepfad. Wir möchten eine interne Sammlungsgröße für Metriken (für Grafana) offenlegen, die von einem anderen Thread gesammelt werden. Der Metrikwert muss nicht perfekt aktuell sein – er muss nur irgendwann sichtbar werden.
Um den Overhead von flüchtigen Feldern oder synchronisierten Lesevorgängen zu vermeiden, verwenden wir einen Wrapper wie diesen:
Code: Select all
public class FastSizeMetric {
private long size;
private static final VarHandle SIZE_HANDLE;
static {
try {
SIZE_HANDLE = MethodHandles.lookup()
.findVarHandle(FastSizeMetric.class, "size", long.class);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
// must be used while holding a lock (any lock/synchronized block will do it)
public void updateSize(final long newSize) {
size = newSize; // plain write
}
public long getSize() {
return (long) SIZE_HANDLE.getOpaque(this);
}
}
Code: Select all
synchronized (jobId-related lock) {
// ... calculations ...
metric.updateSize(map.size());
// ... calculations ...
metric.updateSize(map.size());
// ... calculations ...
}
Fragen:
- Bietet die Durchführung eines einfachen Schreibvorgangs innerhalb eines synchronisierten-Blocks die gleichen eventuellen Sichtbarkeitsgarantien für einen anderen Thread, der getOpaque() aufruft, wie ein explizites setOpaque()?
- Ist ein „Zufälliger“ synchronisierter Block um den Schreibvorgang herum, der ausreicht, um eventuelle Sichtbarkeit für einen undurchsichtigen Lesevorgang sicherzustellen?
- Wird dieses Verhalten durch die Java Memory Model/VarHandle-Spezifikation garantiert, oder handelt es sich lediglich um ein Implementierungsdetail, das zufällig auf aktuellen JDKs funktioniert?
- Kann man sich in zukünftigen JDK-Versionen auf dieses Muster verlassen, oder haben wir heute tatsächlich „Glück“?
Mobile version