CAS概述
Unsafe 是 java 留给开发者的后门,用于直接操作系统内存且不受 jvm 管辖,实现类似 C++ 风格的操作。
Oracle 官方一般不建议开发者使用 Unsafe 类,因为正如这个类的类名一样,它并不安全,使用不当会造成内存泄露。
在平时的业务开发中,这个类基本是不会有接触到的,但是在 java 的并发包和众多偏向底层的框架中,都有大量应用。
值得一提的是,该类的大部分方法均为 native 修饰,即为直接调用的其它语言(大多为 C++)编写的方法来进行操作,很多细节无法追溯,只能大致了解。
本篇演示Unsafe中的CAS使用
CAS对象获取方式
官方获取方式
private static final Unsafe unsafe = Unsafe.getUnsafe();
- 如AQS
AbstractQueuedSynchronizer
直接通过Unsafe.getUnsafe()
的方式获取Unsafe对象 - 但是三方程序通过上述方式获取时,会抛出异常
Caused by: java.lang.SecurityException: Unsafe
@CallerSensitive
public static Unsafe getUnsafe() {
Class<?> caller = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(caller.getClassLoader()))
throw new SecurityException("Unsafe");
return theUnsafe;
}
- 在getUnsafe()方法中,程序会通过
Reflection.getCallerClass()
获取到调用者的class,判断该class的ClassLoader是否是系统类加载器 - jdk有三种类加载器,分别为 系统类加载器,扩展类加载器,应用类加载器
- 上述方法
getUnsafe()
只允许通过系统类加载器加载的调用者调用,其它的类加载器加载的调用者会直接抛出异常 - 即,jdk的开发者,不希望开发者使用该类
反射获取方式
Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeInstance.setAccessible(true);
unsafe = (Unsafe) theUnsafeInstance.get(Unsafe.class);
······
unsafe.compareAndSwapInt(app, valueOffset, 1, 2);
- 可通过反射的方式获取到Unsafe
- 注意
unsafe.compareAndSwapInt(app, valueOffset, 1, 2);
使用的方法一定与值的类型匹配- compareAndSwapInt()方法时对应的1和2应为int类型
- compareAndSwapLong()方法时,对应的1和2应为long类型