2017-04-22 67 views
22

我一直花費很多時間調查一些Java 9的新功能,但我沒有找到任何有用和實用的例子。在Java 9中使用VarHandle的正確方法?

考慮下面的代碼片段,創建一個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) { 
      // ... 
     } 
    } 
} 

但下一步是什麼?我的意思是,如何使用這個變量句柄?你能提供任何真實的例子嗎?

+9

瓦爾手柄(或方法處理)是相當用於方法調用和內存操作的低級API。大多數人將永遠不需要使用這些API。 –

回答

24

它在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,你可能實際上正在訪問完全不同的東西。然而,這樣做會帶來性能上的好處(它告訴虛擬機使用專門的CPU指令),並且因爲其他人已經使用sun.misc.Unsafe,即使它是內部API和不安全 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); 
    } 
}