Java 9 Variable Handles

Java 9 Bootcamp Logo

JEP 193 führt die abstract class java.lang.invoke.VarHandle ein. Damit können Java atomare oder geordnete Operationen auf Feldern einzelner Klassen ausgeführt werden. Dieser Artikel ist ein kleiner Vorgeschmack, was man mit den VarHandles anfangen kann.

Zum Hintergrund

Als eine der Neuerungen von Java 9 ist geplant, dass interne APIs per Voreinstellung nicht mehr allgemein zugänglich sind (JEP 260). Das bedeutet auch, dass Klassen aus den Packages "sun.misc", oder "sun.reflect" nicht mehr genutzt werden können. Diese Anforderung ist zwar aufgeweicht worden, sodass sun.misc.Unsafe zunächst weiter verwendet werden darf, aber es ist das erklärte Ziel sun.misc.Unsafe durch eine offizielle API zu ersetzen. Variable Handles zählen zu den Features, die eingeführt werden um die Zugriffe auf interne APIs wie sun.misc.Unsafe überflüssig zu machen. Zudem sollen auch mehr Möglichkeiten geschaffen werden atomare und geordnete Änderungen an Feldern und Arrays vorzunehmen, ohne den Overhead, den die Verwendung von Klassen aus der Package java.util.concurrent.atomic mit sich bringen.

Was ist ein VarHandle?

JEP 193 hat sich daher zur Aufgabe gemacht, Zugriffe auf Objektfelder und Array-Elemente zu ermöglichen, die so bislang nur mit Hilfe von sun.misc.Unsafe, oder java.util.concurrent.atomic möglich waren. Ein java.base.VarHandle ist eine typisierte Referenz auf eine Variable. Sie erlaubt lesenden und schreibenden Zugriff auf die Variable unter verschiedenen Zugriffsmodi.

Wie komme ich an ein VarHandle?

VarHandle selbst ist eine abstrakte Klasse. Um einen VarHandle zu erhalten, nutzt man die Methode findVarHandle der Klasse MethodHandles. Nehmen wir als Beispiel die Klasse Customer:

class Customer {
    int id;
    // Mehr code ...
}

So erhalten wir einen Varhandle für die id:

static final VarHandle VAR_HANDLE;

static {
    try {
        VAR_HANDLE = MethodHandles.lookup().
            in(Customer.class).
            findVarHandle(Customer.class, "id", int.class);
    } catch (Exception e) {
        throw new Error(e);
    }
}

Der so erhaltene VarHandle unterstützt nur zulässige Zugriffsmodi. Ist das Feld zum Beispiel final, dann werden die Modi write, atomic update, numeric atomic update, und bitwise atomic update nicht zugelassen. Versucht man dennoch die zugehörigen Zugriffsmethoden aufzurufen, erhält man eine UnsupportedOperationException.

Wie benutze ich VarHandles?

Nehmen wir zum Beispiel ein die Operation "compareAndSet". Sie vergleicht den Wert unserer Variable mit einem Sollwert. Ist der Wert gleich dem Sollwert, wird der neue Wert gesetzt, ansonsten nicht. Der Rückgabewert gibt Auskunft über den Erfolg:

Customer c = ...
boolean r = VAR_HANDLE.compareAndSet(c, 0, 1);

VarHandles bieten eine Vielzahl derartiger atomarer Zugriffe auf Variablen und Arrays durch eine einheitliche API.

Wo liegt der Vorteil vom VarHandle?

Normalerweise benötigt man für derartige atomare Operationen auf einem int ein AtomicInteger. Ein AtomicInteger (oder AtomicLong, etc.) sorgt aber für zusätzlichen Overhead. Die Alternative war bislang sun.misc.Unsafe (compareAndSwapInt) zu operieren. Das schränkt aber die Portabilität des Codes ein. VarHandles sind also eine empfehlenswerte und performante Alternative zu einigen der Operationen von sun.misc.Unsafe, oder java.util.concurrent.atomic.

Besuchen Sie unsere Workshops zum Thema Java 9 um mehr über dieses und weitere neue Features von Java 9 zu erfahren: