Java Unsafe CAS 小試
阿新 • • 發佈:2020-08-02
Unsafe
在 Java 標準庫和框架中被大量使用,本文主要介紹如何使用 sun.misc.Unsafe
包實現 CAS 操作。
Example
public class UnsafeExample { private volatile int foo; private static final Unsafe U; private static final long FOO; static { try { // 類載入器限制 無法直接使用 // U = Unsafe.getUnsafe(); // 通過反射 U = getUnsafeByReflection(); Class<?> clazz = UnsafeExample.class; FOO = U.objectFieldOffset(clazz.getDeclaredField("foo")); } catch (Exception e) { throw new Error(e); } } private static Unsafe getUnsafeByReflection() { try { Class<?> unsafeClazz = Class.forName("sun.misc.Unsafe"); Field f = unsafeClazz.getDeclaredField("theUnsafe"); f.setAccessible(true); return (Unsafe) f.get(null); } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) { throw new RuntimeException(e); } } private void casUpdate(int x) { while (true) { final int snapsnot = this.foo; if (U.compareAndSwapInt(this, FOO, snapsnot, x)) break; } } public static void main(String[] args) { UnsafeExample example = new UnsafeExample(); new Thread(() -> { for (int i = 0; i < 100; i++) { example.casUpdate(i); System.out.println(example.foo); } }).start(); new Thread(() -> { for (int i = 100; i < 200; i++) { example.casUpdate(i); System.out.println(example.foo); } }).start(); } }
小結
Unsafe 在 ConcurrentHashMap
使用較多,上方 example 主要借鑑了 ConcurrentHashMap
操作 Unsafe
的方式。
需要注意的是 Unsafe.getUnsafe()
會檢查當前類載入器是否合法,在設定上 Unsafe
僅適用於標準庫等場景,本文通過反射的方式獲取 Unsafe
物件。
直接使用Unsafe.compareAndSwapInt
等方法細節上不同於 AtomicInteger
,需要自行新增自旋邏輯。本質上 AtomicInteger
等類也是藉助 Unsafe
類方法完成 CAS 操作的。下方為 AtomicInteger 相關原始碼:
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!compareAndSwapInt(o, offset, v, v + delta));
return v;
}