Unsafe类是Java中位于sun.misc包下的一个特殊类,它提供了底层的原子性操作和直接内存访问能力,是构建高性能并发数据结构的关键工具。这类操作通常与硬件特性紧密相关,因此对性能有极高的要求。
通常Unsafe的使用应限于JVM和Java核心库的开发者。对于一般的应用程序开发者,推荐使用java.util.concurrent包提供的更安全的并发抽象,这些抽象内部正是借助Unsafe来实现的。
类定义

查看代码
public final class Unsafe {
static {
Reflection.registerMethodsToFilter(Unsafe.class, Set.of("getUnsafe"));
}
private Unsafe() {}
private static final Unsafe theUnsafe = new Unsafe();
private static final jdk.internal.misc.Unsafe theInternalUnsafe = jdk.internal.misc.Unsafe.getUnsafe();
// ...
}public final class Unsafe:Unsafe类被声明为final,这意味着它不能被继承。private Unsafe():构造方法是私有的,防止外部通过new关键字创建Unsafe的实例。
单例实例
private static final Unsafe theUnsafe = new Unsafe();private static final Unsafe theUnsafe:theUnsafe是Unsafe类的一个单例实例,它是在类加载时创建的。
获取Unsafe实例的方法

@CallerSensitive
public static Unsafe getUnsafe() {
Class<?> caller = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(caller.getClassLoader()))
throw new SecurityException("Unsafe");
return theUnsafe;
}public static Unsafe getUnsafe():这是一个公共静态方法,用于返回Unsafe的单例实例。由于这个方法是公共的,它看起来似乎可以随意调用,但实际上,它内部有安全检查,只有当调用它的类是BootstrapClassLoader加载的类时,才会成功,否则会抛出SecurityException。
获取Unsafe类的实例并不直接公开,因为它是一个内部API,设计上不鼓励在普通应用程序中使用。但是,可以通过反射的方式来获取Unsafe的单例实例。
查看代码
import jdk.internal.misc.Unsafe;
import java.lang.reflect.Field;
public class UnsafeExample {
public static void main(String[] args) {
try {
// 通过反射获取Unsafe的theUnsafe字段
Field field = Unsafe.class.getDeclaredField("theUnsafe");
// 设置字段可访问
field.setAccessible(true);
// 获取单例实例
Unsafe unsafe = (Unsafe) field.get(null);
// 现在可以使用unsafe实例进行操作
// 例如: unsafe.allocateMemory(1024); // 分配内存
} catch (Exception e) {
e.printStackTrace();
}
}
}获取
theUnsafe字段:javaField field = Unsafe.class.getDeclaredField("theUnsafe");这里我们使用
getDeclaredField方法获取Unsafe类中名为theUnsafe的字段。设置字段可访问:
javafield.setAccessible(true);由于
theUnsafe字段是私有的,我们需要通过setAccessible(true)来覆盖Java的访问控制检查。获取单例实例:
javaUnsafe unsafe = (Unsafe) field.get(null);通过调用
field.get(null),我们获取了theUnsafe字段的值,即Unsafe的单例实例。
相关操作
Unsafe类提供了大量可以直接操作内存和对象的方法,这些方法大致可以分为以下几类:
内存操作
这些方法允许直接访问和操作内存。
public native long allocateMemory(long bytes);分配一块指定大小的内存空间,并返回基地址。public native long reallocateMemory(long address, long bytes);重新分配给定地址的内存块,返回新的基地址。public native void freeMemory(long address);释放给定地址的内存块。public native void setMemory(Object o, long offset, long bytes, byte value);将给定内存块中的所有字节设置为指定的值。public native void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes);从源内存地址复制指定数量的字节到目标内存地址。public native void copySwapMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes, long elemSize);类似于copyMemory,但会在复制时对每个元素进行字节序转换。
对象操作
这些方法允许直接操作对象和类。
public native Object allocateInstance(Class<?> cls) throws InstantiationException;分配一个类的实例,但不调用任何构造方法。public native long objectFieldOffset(Field f);获取给定字段在对象中的偏移量。public native Object staticFieldBase(Field f);获取给定静态字段的基地址。public native int staticFieldOffset(Field f);获取给定静态字段在类中的偏移量。public native boolean shouldBeInitialized(Class<?> c);确定给定的类是否应该初始化。public native void ensureClassInitialized(Class<?> c);确保给定的类已经被初始化。
原子操作
这些方法提供了原子性操作,常用于实现并发算法。
public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x);原子地比较并交换对象字段。public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);原子地比较并交换整数字段。public final native boolean compareAndSwapLong(Object o, long offset, long expected, long x);原子地比较并交换长整数字段。public native void putOrderedObject(Object o, long offset, Object x);有序地写入对象字段,通常用于构建非阻塞数据结构。public native void putOrderedInt(Object o, long offset, int x);有序地写入整数字段。public native void putOrderedLong(Object o, long offset, long x);有序地写入长整数字段。
线程挂起和恢复
这些方法用于挂起和恢复线程。
public native void unpark(Object thread);唤醒挂起的线程。public native void park(boolean isAbsolute, long time);挂起当前线程,直到被唤醒或超时。
在底层,park可能会调用操作系统的同步原语,如Linux的futex或Windows的WaitOnAddress。
数组操作
这些方法允许直接操作数组。
public native int arrayBaseOffset(Class<?> arrayClass);获取给定数组类型的基地址偏移量。public native int arrayIndexScale(Class<?> arrayClass);获取给定数组类型的索引缩放因子。
内存屏障
这些方法用于创建各种内存屏障,以防止指令重排。
public native void loadFence();在此屏障之前的加载操作全部完成之后,才能执行之后的加载操作。public native void storeFence();在此屏障之前的存储操作全部完成之后,才能执行之后的存储操作。public native void fullFence();在此屏障之前的加载和存储操作全部完成之后,才能执行之后的加载和存储操作。
