Java Unsafe CAS 小试

2020-08-04  本文已影响0人  leeehao

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;
    }
上一篇 下一篇

猜你喜欢

热点阅读