上一讲我们讲述了线程池整个的过程,这一讲我们来先底层的3个组件,synchronized,Unsafe以及LockSupport
Unsafe
常用api
/**
* 获取对象指定Field对应的内存地址偏移量,可以理解为跟C++中的指针一样,获取到了属性的地址,在一个对象中
* 属性的偏移地址是固定的,不会发生变化
* @param var1
* @return
*/
public native long objectFieldOffset(Field var1);
/**
* 可以修改对象属性值
* @param var1 对象实例
* @param var2 属性偏移量
* @param var4 要修改的值
*/
public native void putInt(Object var1, long var2, int var4);
/**
* 获取对象实例
* @param var1
* @return
* @throws InstantiationException
*/
public native Object allocateInstance(Class<?> var1) throws InstantiationException;
/**
* CAS
* @param var1
* @param var2
* @param var4
* @param var5
* @return
*/
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
Unsafe实例的获取
首先从名字就可以看出来这个类是不安全的,比较敏感,所以jdk底层也没有开放使用这个类,该类提供了单利模式获取Unsafe对象的方法:
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
//类加载器必须是root类加载器,否则不允许使用该类
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
所以我们在应用中要获取该类的实例,就得通过反射获取了,反射获取静态私有属性的方式:
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
api实例使用
对象属性偏移量获取
public class UnsafeTest {
private Integer abc = 10;
public UnsafeTest(){
abc = 10;
}
public Integer getAbc() {
return abc;
}
public static void main(String[] args) {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe)theUnsafe.get(null);
Class<UnsafeTest> unsafeTestClass = UnsafeTest.class;
Field[] declaredFields = unsafeTestClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField.getName() + ",偏移地址:" + unsafe.objectFieldOffset(declaredField));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
对象的属性偏移量地址经过编译后,一般不会再发生变化
修改对象属性值
@Test
public void updateObjectField()throws Exception{
Unsafe unsafe = getUnsafe();
UnsafeTest unsafeTest = new UnsafeTest();
Field abc = unsafeTest.getClass().getDeclaredField("abc");
System.out.println(unsafeTest.getAbc());
unsafe.putObject(unsafeTest, unsafe.objectFieldOffset(abc), 40);