2017-04-22 18 views
22

私は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) { 
      // ... 
     } 
    } 
} 

しかし、次は何:

VarHandleを作成し、次のコードスニペットを考えてみましょうか?私は、この使用方法を意味する 可変ハンドル?あなたは本当の例を提供できますか?これは、以前のJava 8、 sun.misc.Unsafeに用いた場合、 AtomicReferenceでインスタンスのために使用される

+9

ヴァールハンドル(またはメソッドハンドル)かなりありますメソッド呼出しとメモリ操作のための低レベルのAPIほとんどの人は、これらのAPIを使用する必要はありません。 –

答えて

24

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を使用しています。

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にこれらのメソッドは次のようになります。VALUEはこのようVarHandle定義され

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

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

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); 
    } 
} 
関連する問題