在Java 9中使用VarHandle的正确方法?

时间:2017-04-22 10:45:56

标签: java 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) {
            // ...
        }
    }
}

但下一步是什么?我的意思是,如何使用这个变量句柄?你能提供任何真实的例子吗?

1 个答案:

答案 0 :(得分:29)

例如在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使用专门的CPU指令),并且因为其他人使用了sun.misc.Unsafe,即使它是内部的,而且不安全的 API。

VarHandles的部分目的是用安全的等价物替换sun.misc.Unsafe中的操作。这在the 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);
}

其中VALUEVarHandle定义如下:

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