赞
踩
什么是CAS
CAS英文全称为Compare And Swap,比较并交换的意思。CAS操作包含3个参数-----V,E,N。V代表着要更新的变量(也可以理解为内存地址),E代表着预期原值,N代表着新值。CAS操作采用了乐观锁的思想,判断逻辑是只有在V的值等于E值时,才会将V的值设置为N。如果V的值和E值不想等,说明有别的线程先修改了E值,当前线程不做任何操作。到最后,CAS会返回当前V被其他线程修改过后的值。
分析AtomicInteger类的CAS操作
JDK的原子包java.util.concurrent.atomic提供了一堆的原子类,他们内部都是基于CAS算法实现的。现在选择其中之一的AtomicInteger类,分析它的方法 —— getAndIncrement() ,加深对CAS操作的印象。
public class AtomicInteger extends Number implements java.io.Serializable { private static final long serialVersionUID = 6214790243416807050L; // setup to use Unsafe.compareAndSwapInt for updates private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; static { try { //获取value字段在内存中的地址相对于实例对象内存地址的偏移量 valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } private volatile int value; //返回当前值 public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); } public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { //获得给定对象的指定偏移量offset的int值 var5 = this.getIntVolatile(var1, var2); //一直进行CAS操作,直到成功 } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; } // var1--操作的对象 // var2--偏移量 // var4--预期原值 // var5--要修改的值 //比较并交换----本地方法,方法参数var1+var2就是具体的内存地址了 public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5); //获取value值 public final int get() { return value; } }
以上是getAndIncrement涉及的源码,接下来写段测试代码,来直观的感受下CAS操作:
测试代码如下:
public class TestMain {
public static void main(String[] args) throws Exception {
AtomicInteger atomicInteger = new AtomicInteger();
int oldAtomicInteger1 = atomicInteger.getAndIncrement();
System.out.println("第一次自增的旧值=" + oldAtomicInteger1);
System.out.println("第一次自增的新值=" + atomicInteger.get());
int oldAtomicInteger2 = atomicInteger.getAndIncrement();
System.out.println("第二次自增的旧值=" + oldAtomicInteger2);
System.out.println("第二次自增的新值=" + atomicInteger.get());
}
}
运行结果如下:
从结果里可以知道,在调用方法getAndIncrement后,返回的是原值,同时atomicInteger对象完成了自增。
接下来打上断点,看看数据验证下想法:
第一次自增:
通过断点可以知道对象值var1为0,偏移量var2为12,这两个字段确定了内存地址,同时预期原值var5值为0
,要修改的值为var5+var4=1。根据CAS操作,要更新的变量值为0,等于预期原值,所以更新AtomicInteger对象的value为1。
继续断点:
可以看到在这步操作中,要更新的变量值已经变为了1,同时返回预期原值0。
符合第一次自增操作的结果:
继续第二步自增操作:
通过断点可以知道此时对象值var1为1,偏移量var2为12,这两个字段确定了内存地址,同时预期原值var5值为1
,要修改的值为var5+var4=2。根据CAS操作,要更新的变量值为1,等于预期原值,所以更新AtomicInteger对象的value为2。
继续断点:
可以看到在这步操作中,要更新的变量值已经变为了2,同时返回预期原值1。
符合第二次自增操作的结果:
总结
初步了解CAS操作后,我们可以发现,即使不使用锁,一样可以实现当前执行操作的线程对其他线程的排他性,实现原子性的操作,不过CAS也是有它自己的缺陷的,比如ABA问题和循环时间过长开销会很大等,但这并不影响我们对CAS操作逻辑的理解。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。