Подтвердить что ты не робот

Правильный способ использования VarHandle в Java 9?

Я потратил много времени на изучение некоторых новых возможностей Java 9, но я не нашел полезных и практических примеров.

Рассмотрим следующий фрагмент кода, который создает 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) {
            // ...
        }
    }
}

Но что дальше? Я имею в виду, как использовать эту ручку переменной? Можете ли вы представить какие-либо реальные примеры?

4b9b3361

Ответ 1

Он используется, например, в AtomicReference, где ранее в Java 8 использовался sun.misc.Unsafe:

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);
}

Здесь указатель this используется вместе со смещением поля для доступа к полю. Но это небезопасно, поскольку это смещение поля может быть любым long, и вы действительно можете получить доступ к чему-то совершенно другому. тем не менее, есть преимущества в производительности при выполнении этого способа (он указывает VM на использование специализированных инструкций процессора, например), и из-за этого другие люди использовали sun.misc.Unsafe, хотя это внутренний и небезопасный API.

Частично для VarHandles необходимо заменить операции в sun.misc.Unsafe безопасным эквивалентом. Что указано в JEP:

Определите стандартное средство для вызова эквивалентов различных действий java.util.concurrent.atomic и sun.misc.Unsafe...

Цель:

Требуются следующие цели:

  • Безопасность. Невозможно разместить виртуальную машину Java в коррумпированном состоянии памяти. Например, поле объекта может быть обновлено только экземплярами, которые могут быть отнесены к типу поля, или элемент массива может быть доступен только внутри массива, если индекс массива находится в пределах массива.

  • Целостность

    . Доступ к полю объекта следует тем же правилам доступа, что и к байтовым кодам getfield и putfield в дополнение к ограничению, которое невозможно обновить окончательное поле объекта. (Примечание: такие правила безопасности и целостности также применяются к MethodHandles, предоставляющим доступ к чтению или записи в поле.)

  • Производительность

    . Эксплуатационные характеристики должны быть такими же, как или аналогичные эквивалентным sun.misc.Unsafe(в частности, сгенерированный код ассемблера должен быть почти идентичным по модулю определенных проверок безопасности, которые нельзя отложить).

  • Юзабилити. API должен быть лучше, чем sun.misc.Unsafe API.

Итак, в Java 9 эти методы выглядят следующим образом:

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

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

Где VALUE - это VarHandle, например:

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);
    }
}