java Unsafe类的compareAndSwap方法
前言
compareAndSwap是个原子方法,原理是cas。就是说如果他是xx,那么就改为xxx。
这个是高效,而且是原子的,不用加锁。
也不会因为其他值改了而产生误操作,因为会先判断当前值,符合期望才去改变。
测试代码如下:
1 package com.example.mass_study.test01.anything; 2 3 /** 4 * @description: 5 * @author: luguilin 6 * @date: 2022-04-15 14:44 7 **/ 8 9 import java.lang.reflect.Field; 10 11 import sun.misc.Unsafe; 12 13 14 public class UnsafeTest { 15 16 private static Unsafe unsafe; 17 18 static { 19 try { 20 //通过反射获取rt.jar下的Unsafe类 21 Field field = Unsafe.class.getDeclaredField("theUnsafe"); 22 field.setAccessible(true); 23 unsafe = (Unsafe) field.get(null); 24 } catch (Exception e) { 25 System.out.println("Get Unsafe instance occur error" + e); 26 } 27 } 28 29 public static void main(String[] args) throws Exception { 30 Class clazz = Target.class; 31 Field[] fields = clazz.getDeclaredFields(); 32 System.out.println("fieldName:fieldOffset"); 33 for (Field f : fields) { 34 // 获取属性偏移量,可以通过这个偏移量给属性设置 35 System.out.println(f.getName() + ":" + unsafe.objectFieldOffset(f)); 36 } 37 Target target = new Target(); 38 Field intFiled = clazz.getDeclaredField("intParam"); 39 int a = (Integer) intFiled.get(target); 40 System.out.println("原始值是:" + a); 41 //intParam的字段偏移是12 原始值是3 我们要改为10 42 System.out.println(unsafe.compareAndSwapInt(target, 12, 3, 10)); 43 int b = (Integer) intFiled.get(target); 44 System.out.println("改变之后的值是:" + b); 45 46 //这个时候已经改为10了,所以会返回false 47 System.out.println(unsafe.compareAndSwapInt(target, 12, 3, 10)); 48 49 System.out.println(unsafe.compareAndSwapObject(target, 24, null, "5")); 50 } 51 } 52 53 class Target { 54 int intParam = 3; 55 long longParam; 56 String strParam; 57 String strParam2; 58 }
结果如下:
1 fieldName:fieldOffset 2 intParam:12 3 longParam:16 4 strParam:24 5 strParam2:28 6 原始值是:3 7 true 8 改变之后的值是:10 9 false 10 true
compareAndSwapInt是通过反射根据字段偏移去修改对象的,可以看到int是4个字节的偏移量,long是8个字节的偏移量,string是4个字节的偏移量
注意:Unsafe的对象不能直接new,要通过反射去获取。