Unsafe类
Unsafe类简单来说就是不安全的类,因为是直接拿到数据的真实内存地址,直接操作内存,脱离于语言本身。里面的方法基本都是native方法。
1. Java中的CAS操作
使用锁处理并发问题,有一个缺点就是线程没有获取到锁的时候会被阻塞挂起,这会导致线程上下文的切换和重新调度开销。由于volatile不能解决原子性问题,Java中由JDK提供的非阻塞原子性操作,即CAS(Compare and Swap)。它通过硬件保证比较-更新的原子性。
CAS操作有个经典的ABA问题,感兴趣的可以百度看一看。解决方案:可以给每个变量加上时间戳。
2. Unsafe类中的重要方法
如何获取
不能直接通过调用功能getUnsafe方法来得到Unsafe,因为其方法会判断是否使用Bootstrap加载器加载类的。其原因是Unsafe类是直接操作内存,这样很不安全。
// 所以我们只能通过反射来获取
public static Unsafe getUnsafe() throws NoSuchFieldException, IllegalAccessException {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
// 设置其为可访问的
field.setAccessible(true);
return (Unsafe) field.get(null);
}
objectFieldOffset()方法
// 本地方法
public native long objectFieldOffset(Field var1);
案例
// AQS类使用该方法,获取所属类中的内存偏移地址,提供给Unsafe类其他方法使用,改变其值
static {
try {
stateOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("state"));
....
} catch (Exception ex) { throw new Error(ex); }
}
compareAndSwapObject()方法
compareAndSwap的意思是比较并交换
,CAS有四个操作数,分别为:对象的内存位置,对象中变量的偏移量,变量预期值,新的值
public final native boolean compareAndSwapObject(Object var1, long valueOffset, Object expect, Object update);
案例
// AQS中修改state变量的值
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
getLongVolatile()方法
获取对象obj中偏移量为offset的变量对应volatile语义的值
public native long getLongVolatile(Object obj, long offset);
getAndSetLong()方法
该方法是获取当前变量的值,然后使用CAS原子操作设置新值。如果更新失败(多个线程同时更新变量的值时
),则重新再次尝试。
public final long getAndSetLong(Object var1, long offset, long var4) {
long var6;
do {
var6 = this.getLongVolatile(var1, offset);
// 如果设置失败,会循环再次设置,知道成功
} while(!this.compareAndSwapLong(var1, offset, var6, var4));
return var6;
}
案例
AtomicLong类
,Java中的原子类都是调用Unsafe类的CAS操作来完成院子操作的。同时提醒一个点:单个原子类的操作是具有原子性的,但是多个组合就不具有了
public final long getAndSet(long newValue) {
return unsafe.getAndSetLong(this, valueOffset, newValue);
}
getAndAddLong()方法
获取对象obj中偏移量为offset的变量volatile语义值,并设置其值=原始值+addValue
public final long getAndAddLong(Object obj, long offset, long addValue) {
long var6;
do {
var6 = this.getLongVolatile(obj, offset);
// 如果设置失败,会循环再次设置,知道成功
} while(!this.compareAndSwapLong(obj, offset, var6, var6 + addValue));
// 返回的还是原始值
return var6;
}
案例
// 调用Unsafe类的方法,原子性设置value的值加1,并返回value原来的值
public final long getAndIncrement() {
return unsafe.getAndAddLong(this, valueOffset, 1L);
}
park()、unpark()
park(boolean isAbsolute, long time):阻塞当前线程
unpark(Object thread):唤醒调用park阻塞的线程
LockSupport
他提供了基本的使用方法,类似于Unsafe的直接操作,他可以间接操作。基本上是对Unsafe类的park和unpark方法封装,但增加了一些额外的提示信息(比如:可以在线程堆栈信息查看到更多有关阻塞对象的信息
)。
版权属于:作者名称
转载时须注明出处及本声明