Unsafe是JAVA提供偏底层的一个工具类,提供堆外内存管理,CAS操作,线程调度等功能。
Unsafe这个类不能直接获取,需要用反射获取其对象。
//反射拿到Unsafe对象
private static Unsafe reflectGetUnsafe() {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
return (Unsafe) field.get(null);
} catch (Exception e) {
return null;
}
}
Unsafe管理堆外内存的代码示例
public static void actionMemory() {
Unsafe unsafe = reflectGetUnsafe();
//分配10个字节的内存,返回值为内存基础地址
long address = unsafe.allocateMemory(10);
//传入基础地址,长度10, byte-0,初始化堆外内存
unsafe.setMemory(address, 10L, (byte) 0);
//传入内存地址位置设置byte值
unsafe.putByte(address, (byte) 1);
unsafe.putByte(address+1, (byte) 2);
unsafe.putByte(address+2, (byte) 3);
//根据内存地址获取byte值
System.out.println(unsafe.getByte(address));
System.out.println(unsafe.getByte(address+1));
System.out.println(unsafe.getByte(address+2));
//释放内存
unsafe.freeMemory(address);
}
Unsafe.getAndAddInt原子增加方法。
//o为对象 offset为对象属性的内存地址 delta为数值
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
//v为旧值,这里可能并发,多个线程同时拿到相同的值
v = getIntVolatile(o, offset);
//传入旧值v 跟新值v + delta,这里也是并发调用
//compareAndSwapInt方法保证只有一个线程能够对变量赋值v + delta,
//那么此时其它线程传入的仍然是旧值V,显然不会成功,那么会继续循环
} while (!compareAndSwapInt(o, offset, v, v + delta));
return v;
}
Unsafe.compareAndSwapInt方法,传入预期值和新值,如果变量的值等于预期值才会把新值赋值给变量,此方法虚拟机底层实现,保证了现场安全,不会有俩个线程同时更新。
public final native boolean compareAndSwapInt(Object o, long offset,
int expected,
int x);