Unsafe类是Java中的一个特殊类,位于sun.misc包下。它提供了一系列方法,用于执行低级别的、不安全的操作,如直接访问系统内存资源和自主管理内存资源等。这些方法在提升Java程序的运行效率和增强对底层资源的操作能力方面起到了重要作用。
然而,Unsafe类的使用也带来了一定的风险。由于它赋予了Java类似C语言指针操作内存空间的能力,过度或不正确地使用Unsafe类可能导致程序出现指针相关的问题,从而增加了出错的概率。这使得原本安全的Java语言变得不再"安全"。因此,在使用Unsafe类时需要格外谨慎。
需要注意的是,尽管Unsafe类的方法都是public的,但并不意味着可以随意使用它们。JDK API文档也没有提供关于这个类方法的解释。对于Unsafe类的使用是受到限制的,只有经过授权的代码才能获得该类的实例。当然,JDK库中的类是可以随意使用Unsafe类的。
Unsafe 类的主要作用大致为:
- 内存管理:Unsafe 类可以用于分配和释放内存,允许开发者直接操作内存资源。
- 非常规的对象实例化:Unsafe 允许不通过构造函数创建对象实例。
- 操作类、对象、变量:可以对类、对象和变量进行底层操作,如通过内存偏移地址访问对象的属性等。
- 自定义超大数组操作:支持超过普通数组界限的数组操作。
- 多线程同步:提供锁机制、CAS(Compare And Swap)操作等多线程同步功能。
- 线程挂起与恢复:能够挂起和恢复线程的执行。
- 内存屏障:用于控制指令重排,保证内存操作的顺序性。
以下是几个cas方法:
public final int getAndAddInt(Object paramObject, long paramLong, int paramInt)
{
int i;
do
i = getIntVolatile(paramObject, paramLong);
while (!compareAndSwapInt(paramObject, paramLong, i, i + paramInt));
return i;
}
public final long getAndAddLong(Object paramObject, long paramLong1, long paramLong2)
{
long l;
do
l = getLongVolatile(paramObject, paramLong1);
while (!compareAndSwapLong(paramObject, paramLong1, l, l + paramLong2));
return l;
}
public final Object getAndSetObject(Object paramObject1, long paramLong, Object paramObject2)
{
Object localObject;
do
localObject = getObjectVolatile(paramObject1, paramLong);
while (!compareAndSwapObject(paramObject1, paramLong, localObject, paramObject2));
return localObject;
}
从源码中发现,内部使用自旋的方式进行CAS更新(while循环进行CAS更新,如果更新失败,则循环再次重试)。
Unsafe提供的3种CAS方法:
- compareAndSwapObject
- compareAndSwapInt
- compareAndSwapLong
以下是以序列图表示compareAndSwapInt方法如何在并发环境中被调用:
Unsafe的cas底层
Unsafe的compareAndSwap*方法来实现CAS操作,它是一个本地方法,实现位于unsafe.cpp中。
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
UnsafeWrapper("Unsafe_CompareAndSwapInt");
oop p = JNIHandles::resolve(obj);
jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END
Unsafe其它功能
Unsafe 提供了硬件级别的操作,比如说获取某个属性在内存中的位置,比如说修改对象的字段值,即使它是私有的。不过 Java 本身就是为了屏蔽底层的差异,对于一般的开发而言也很少会有这样的需求。
获取paramField 的内存地址偏移量:
public native long staticFieldOffset(Field paramField);
分配内存:
public native long allocateMemory(long paramLong);
扩充内存:
public native long reallocateMemory(long paramLong1, long paramLong2);
释放内存:
public native void freeMemory(long paramLong);
总结
由于 Unsafe 类提供了类似 C 语言指针的操作能力,过度或不正确使用可能会增加程序出错的风险,导致 Java 语言变得不再“安全”。因此,在使用 Unsafe 类时必须非常谨慎,并确保充分理解其工作原理和潜在风险。
值得注意的是,Unsafe 类的实现依赖于本地方法(Native Method),这些本地方法是用其他编程语言编写的,并且与操作系统底层紧密相关。