Reicht ein einfacher Schreibvorgang innerhalb eines synchronisierten Blocks aus, um getOpaque() eventuell sichtbar zu maJava

Java-Forum
Anonymous
 Reicht ein einfacher Schreibvorgang innerhalb eines synchronisierten Blocks aus, um getOpaque() eventuell sichtbar zu ma

Post by Anonymous »

Aus „Using JDK 9 Memory Order Modes“ von Doug Lea:

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);
}
}
Die Metrik wird immer aktualisiert, solange eine unabhängige Sperre besteht:

Code: Select all

    synchronized (jobId-related lock) {
// ... calculations ...
metric.updateSize(map.size());
// ... calculations ...
metric.updateSize(map.size());
// ... calculations ...
}
Der Metrik-Collector-Thread ruft getSize() regelmäßig mit getOpaque() auf.
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“?
TL;DR: Ist ein durch Synchronisierung geschützter einfacher Schreibvorgang + ein undurchsichtiger Lesevorgang ein gültiges und zukunftssicheres Muster für Low-Fidelity-Metriken, oder sollten wir explizit setOpaque() (oder stärker) verwenden?

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post