[toc]
Unsafe基础
Unsafe类是整个Concurrent包的基础,里面所有函数都是native的。具体到compareAndSwapInt函数,如下所示。
1 | public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5); |
该函数有4个参数。在前两个参数中,第一个是对象(也就是AtomicInteger 对象),第二个是对象的成员变量(也就是AtomictInteger里面包的int变量value),后两个参数保持不变。
long类型的也是同理
1 | public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6); |
AutomicInteger源码阅读
1 |
|
初始化静态代码块
使用static说明是类级别的,所有实例对象公用的,在转化的时候,先通过反射(getDeclaredField)获取value成员变量对应的Field对象,再通过objectFieldOffset函数转化成valueOffset。此处的valueOffset就代表了value变量本身,后面执行CAS操作的时候,不是直接操作value,而是操作valueOffset。
1 | static { |
真实保存的值
1 | // 当前的值,对其进行CAS操作 |
1 | // 创建给定初值的AutomicInteger对象 |
AtomicInteger封装过的compareAndSet有两个参数。第一个参数expect是指变量的旧值(是读出来的值,写回去的时候,希望没有被其他线程修改,所以称为expect);第二个参数update是指变量的新值(修改过的,希望写入的值)。当expect等于变量当前的值时,说明在修改的期间,没有其他线程对此变量进行过修改,所以可以成功写入,变量被更新为update,返回true;否则返回false。
1 | // 利用CAS保存当前的值 |
weakCompareAndSet方法
一个原子类也支持weakCompareAndSet方法,该方法有适用性的限制。在一些平台上,在正常情况下weak版本比compareAndSet更高效,但是不同的是任何给定的weakCompareAndSet方法的调用都可能会返回一个虚假的失败( 无任何明显的原因 )。一个失败的返回意味着,操作将会重新执行,如果需要的话,重复操作依赖的保证是当变量持有expectedValue的值并且没有其他的线程也尝试设置这个值将最终操作成功。( 一个虚假的失败可能是由于内存冲突的影响,而和预期值(expectedValue)和当前的值是否相等无关 )。此外weakCompareAndSet并不会提供happen-before排序的保证,即通常需要用于同步控制的排序保证。然而,这个方法可能在修改计数器或者统计,这种修改无关于其他happens-before的程序中非常有用。当一个线程看到一个通过weakCompareAndSet修改的原子变量时,它不被要求看到其他变量的修改,即便该变量的修改在weakCompareAndSet操作之前。
weakCompareAndSet底层不会创建任何happen-before的保证,也就是不会对volatile字段操作的前后加入内存屏障。因此就无法保证多线程操作下对除了weakCompareAndSet操作的目标变量( 该目标变量一定是一个volatile变量 )之其他的变量读取和写入数据的正确性。
1 |
|
AutomicLong源码阅读
AutomicLong的实现与AutomicInteger的源码实现基本一致,除了多了两个字段判断JVM是否支持Long类型的CAS操作
1 | package java.util.concurrent.atomic; |
VM_SUPPORTS_LONG_CAS:虚拟机是否支持CAS操作
1 | /** |
1 | static { |
参考文献
对 volatile、compareAndSet、weakCompareAndSet 的一些思考
<<java并发实现原理:JDK源码刨析>>