compareAndSwap是个原子方法,原理是CAS,即将内存中的值与期望值进行比较,如果相等,就将内存中的值修改成新值并返回true。
package com.java.magic.part4.exception;
import java.lang.reflect.Field;
import sun.misc.Unsafe;
class Target{
int intParam = 3;
long longParam;
String strParam;
}
public class UnsafeTest {
private static Unsafe unsafe;
static{
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
unsafe = (Unsafe)field.get(null);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
Class clazz = Target.class;
Field[] fields = clazz.getDeclaredFields();
System.out.println("fieldNameeeee:fieldOffset");
for(Field f : fields){
//获取属性偏移量,可以通过这个偏移量给属性设值
System.out.println(f.getName()+" : "+unsafe.objectFieldOffset(f));
}
System.out.println("--------------------------------");
Target target = new Target();
Field intParam = clazz.getDeclaredField("intParam");
int a = (Integer) intParam.get(target);
System.out.println("intParam原始值:"+a);
long intParamOffset = unsafe.objectFieldOffset(intParam);
System.out.println("intParam实例变量偏移量:"+intParamOffset);
//intParam实例变量偏移量是offset 原始值是3,我们要改成10
System.out.println(unsafe.compareAndSwapInt(target, intParamOffset, 3, 10));
System.out.println("intParam改变之后的值:"+target.intParam);
System.out.println("--------------------------------");
//这个时候已经改为10了,所以会返回false
System.out.println(unsafe.compareAndSwapInt(target, intParamOffset, 3, 10));
System.out.println("--------------------------------");
Field strParam = clazz.getDeclaredField("strParam");
String str = (String) strParam.get(target);
System.out.println("strParam原始值:"+str);
long strParamOffset = unsafe.objectFieldOffset(strParam);
System.out.println("strParam实例变量的偏移量是:"+strParamOffset);
System.out.println(unsafe.compareAndSwapObject(target, strParamOffset, null, "5"));
System.out.println("strParam改变之后的值:"+target.strParam);
}
}
运行结果如下:
compareAndSwapInt是通过调用本地方法根据字段偏移去修改对象属性的.
可以看到int是4个字节的偏移量,long是8个字节的偏移量
注意:Unsafe的对象不能直接new,这里通过反射去获取Unsafe里面的私有成员变量theUnsafe