JUC-Unsafe简介

Unsafe

Unsafe 是 CAS 的核心类,由于 Java 无法直接访问底层系统,需要通过本地(Native)方法来访问

Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全操作的方法,如直接访问系统内存资源、自主管理内存资源等,这些方法在提升Java运行效率、增强Java语言底层资源操作能力方面起到了很大的作用。但由于Unsafe类使Java语言拥有了类似C语言指针一样操作内存空间的能力,这无疑也增加了程序发生相关指针问题的风险。在程序中过度、不正确使用Unsafe类会使得程序出错的概率变大,使得Java这种安全的语言变得不再“安全”,因此对Unsafe的使用一定要慎重。

Unsafe类中的重要方法

Unsafe类提供了硬件级别的的原子性操作,Unsafe类中的方法都是native方法,通过使用JNI的方式访问本地C++库

  • long objectFieldOffset(Field field) 方法: 返回指定的变量在所属类中的内存偏移地址
  • int arrayBaseOffset(Class arrayClass) 方法: 获取数组中第一个元素的地址
  • boolean compareAndSwapLong(Object obj, long offset, long expect, long update) 方法: CAS操作
  • public native long getLongvolatile(Object obj, long offset) 方法: 获取对象obj中偏移量offset 的变量对应volatile语义的值
  • void putLongvolatile(Object obj, long offset, long value)方 法: 设置 obj 对 象 中 offset偏移的类型为 long 的 field 的值为 value ,支持 volatile 语义
  • void park(boolean isAbsolute, long time) 方法: 阻塞当前线程
  • void unpark(Object thread) 方法: 唤醒调用park后阻塞的线程
  • long getAndSetLong(Object obj , long offset, long update) 方法: 获取对象 obj 中偏移量为offset 的变量 volatile语义的当前值 ,并设置变量 volatile 语义的值为 update
  • long getAndAddLong(Object obj, long offset, long addValue) 方法: 获取对象obj中偏移量为 offset 的变量 volatile 语义的当前值 ,并设置变量值为原始值+addValue

模拟实现原子整数

Unsafe类为一单例实现,提供静态方法getUnsafe获取Unsafe实例,当且仅当调用getUnsafe方法的类为引导类加载器所加载时才合法,否则抛出SecurityException异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public static void main(String[] args) {
MyAtomicInteger atomicInteger = new MyAtomicInteger(10);
if (atomicInteger.compareAndSwap(20)) {
System.out.println(atomicInteger.getValue());
}
}

class MyAtomicInteger {
private static final Unsafe UNSAFE;
private static final long VALUE_OFFSET;
private volatile int value;

static {
try {
//Unsafe unsafe = Unsafe.getUnsafe()这样会报错,只能通过反射获取
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
UNSAFE = (Unsafe) theUnsafe.get(null);
// 获取 value 属性的内存地址,value 属性指向该地址,直接设置该地址的值可以修改 value 的值
VALUE_OFFSET = UNSAFE.objectFieldOffset(
MyAtomicInteger.class.getDeclaredField("value"));
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException();
}
}

public MyAtomicInteger(int value) {
this.value = value;
}
public int getValue() {
return value;
}

public boolean compareAndSwap(int update) {
while (true) { // 自旋
int prev = this.value;
int next = update;
// 当前对象 内存偏移量 期望值 更新值
if (UNSAFE.compareAndSwapInt(this, VALUE_OFFSET, prev, update)) { // Unsafe提供的CAS方法(如compareAndSwapXXX)底层实现即为CPU指令cmpxchg。
System.out.println("CAS成功");
return true;
}
}
}
}

详细内容参考:https://zhuanlan.zhihu.com/p/56772793

文章作者: GeYu
文章链接: https://nuistgy.github.io/2023/04/25/JUC-Unsafe/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yu's Blog