java不能直接访问操作系统底层,而是通过native本地方法来访问。Unsafe类提供了硬件级别的原子操作
juc并发包,即java.util.concurrent包,是JDK的核心工具包,是JDK1.5之后,由 Doug Lea实现并引入。整个java.util.concurrent包,按照功能可以大致划分如下:
juc-locks 锁框架
juc-atomic 原子类框架
juc-sync 同步器框架
juc-collections 集合框架
juc-executors 执行器框架
public final class Unsafe {
private Unsafe() {} //私有化构造器,外界不能访问
static {theUnsafe = new Unsafe();}
//提供反射获取Unsafe实例的方法
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
}
return theUnsafe;
}
//获取var1的实际地址偏移值,是一个native本地方法
public native long objectFieldOffset(Field var1);
/**
* cas更新var2对应的属性值
* @param var1 操作的对象
* @param var2 操作的对象属性地址相对偏移值,通过var1和var2获取当前对象属性的当前值
* @param var4 期望值
* @param var5 新值
*/
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
//通过target对象和对象中元素的偏移地址在内存中找到指定元素的实际值
public native int getIntVolatile(Object target, long offset);
//获取target对象中相对偏移offset地址的值
public native int getInt(Object target, long offset);
/**
*@param target 指定内存对象
*@param offset 该内存对象中需要操作的对象偏移量
*@param expectValue 期望值expectValue
*@param newValue 新值newValue
*@return true cas更新成功 false cas更新失败
*/
public final native boolean compareAndSwapInt(Object target, long offset, int expectValue, int newValue);
/**
* getAndAddInt方法解析:拿到内存位置的最新值v,使用CAS尝试修将内存位置的值修改为目标值v+delta,如果修改失败
* 则获取该内存位置的新值v,然后继续尝试,直至修改成功
*
*@param target 内存对象
*@param offset 该内存对象中需要操作的对象偏移量
*@param var4 增量
*/
public final int getAndAddInt(Object target, long offset, int var4) {
int var5;
//while循环尝试更新offset对应的对象元素值,知道成功才会退出,期间一直占据cpu
do {
//通过对象地址和相对地址获取内存数据var5即变量"value"
//不停的while循环开销很大
var5 = this.getIntVolatile(target, offset);
} while(!this.compareAndSwapInt(target, offset, var5, var5 + var4));
return var5;
}
public native long allocateMemory(long l); //分配内存
public native long reallocateMemory(long l, long l1); //扩充内存
public native void freeMemory(long l); //释放内存
//返回指定类型数组的第一个元素相对于数组起始地址的偏移值,例如arrayClass=String[].class
public native int arrayBaseOffset(Class arrayClass);
// 获取用户给定数组寻址的换算因子,也就是数组中元素的增量地址,是2的幂次方
public native int arrayIndexScale(Class<?> var1); //将arrayBaseOffset与arrayIndexScale配合使用,可以定位数组中每个元素在内存中的位置。
//eg:获取array数组中下标为i的元素
//计算i位置元素的地址偏移
//long ABASE = unsafe.arrayBaseOffset(String[].class); //计算String[].class的首元素地址偏移
//int SCALE = unsafe.arrayIndexScale(String[].class); //计算每个String类型元素的增量地址
//int ASHIFT = 31 - Integer.numberOfLeadingZeros(SCALE);
//long offset = ABASE + i * SCALE; //计算偏移地址(method1)
//long offset = ABASE + i << ASHIFT; //计算偏移地址(method2)
//String obj= (String) unsafe.getObject(array, ((long) i << ASHIFT) + ABASE);
//设置obj对象中offset偏移地址对应的整型field的值为指定值。这是一个有序或者有延迟的<code>putIntVolatile</cdoe>方法,并且不保证值的改变被其他线程立即看到。只有在field被<code>volatile</code>修饰并且期望被意外修改的时候使用才有用。
public native void putOrderedInt(Object obj, long offset, int value);
//设置obj对象中offset偏移地址对应的整型field的值为指定值。支持volatile store语义
public native void putIntVolatile(Object obj, long offset, int value);
//释放被park创建的在一个线程上的阻塞
public native void unpark(Thread thread);
//阻塞一个线程直到unpark出现、线程被中断或者timeout时间到期。如果一个unpark调用已经出现了,这里只计数。timeout为0表示永不过期
public native void park(boolean isAbsolute, long time);
}