Correct way to use VarHandle in Java 9?

Oleksandr Pyrohov :

I have been spending much time investigating some of Java 9's new features, but I didn't find any useful and practical examples.

Consider next code snippet that creates a VarHandle:

class Counter {
    int i;
}

class VarHandleInAction {
    static final VarHandle VH_COUNTER_FIELD_I;

    static {
        try {
            VH_COUNTER_FIELD_I = MethodHandles.lookup()
                .in(Counter.class)
                .findVarHandle(Counter.class, "i", int.class);
        } catch (Exception e) {
            // ...
        }
    }
}

But what's next? I mean, how to use this Variable Handle? Can you provide any real examples?

Jorn Vernee :

It is used for instance in AtomicReference, where previously in Java 8, sun.misc.Unsafe was used:

public final void lazySet(V newValue) {
    unsafe.putOrderedObject(this, valueOffset, newValue);
}

public final boolean compareAndSet(V expect, V update) {
    return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}

Here the this pointer is used together with a field offset to access the field. But this is unsafe, since this field offset could be any long, and you might actually be accessing something completely different. There are however performance benefits in doing it this way (it tells the VM to use specialized CPU instructions for instance), and because of that other people have used sun.misc.Unsafe even though it's an internal, and unsafe API.

Part of the purpose for VarHandles is to replace operations in sun.misc.Unsafe with a safe equivalent. Which is stated in the JEP:

Define a standard means to invoke the equivalents of various java.util.concurrent.atomic and sun.misc.Unsafe operations...

Goals:

The following are required goals:

  • Safety. It must not be possible to place the Java Virtual Machine in a corrupt memory state. For example, a field of an object can only be updated with instances that are castable to the field type, or an array element can only be accessed within an array if the array index is within the array bounds.

  • Integrity. Access to a field of an object follows the same access rules as with getfield and putfield byte codes in addition to the constraint that a final field of an object cannot be updated. (Note: such safety and integrity rules also apply to MethodHandles giving read or write access to a field.)

  • Performance. The performance characteristics must be the same as or similar to equivalent sun.misc.Unsafe operations (specifically, generated assembler code should be almost identical modulo certain safety checks that cannot be folded away).

  • Usability. The API must be better than the sun.misc.Unsafe API.

So in Java 9 these methods look like this:

public final void lazySet(V newValue) {
    VALUE.setRelease(this, newValue);
}

public final boolean compareAndSet(V expectedValue, V newValue) {
    return VALUE.compareAndSet(this, expectedValue, newValue);
}

Where VALUE is a VarHandle define like this:

private static final VarHandle VALUE;
static {
    try {
        MethodHandles.Lookup l = MethodHandles.lookup();
        VALUE = l.findVarHandle(AtomicReference.class, "value", Object.class);
    } catch (ReflectiveOperationException e) {
        throw new Error(e);
    }
}

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=419849&siteId=1