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;
}
网友评论