cas(CompareAndSet)号称无锁优化,或者叫自旋,也被叫做乐观锁。这个名字无所谓,重要的是这个东西是做什么的。
由于某一些特别常见的操作,老是来回的加锁,加锁的情况特别多,所以java就直接提供了这些常见的操作,也就是以Atomic开头的类,这些类的内部就自动带了锁,当然这些锁的实现并不是synchronize重量级锁,而是CAS的操作来实现的。(号称无锁)
凡是以Atomic开头的都是用CAS这种操作来保证线程安全的这么一些个类。AtomicInteger的意思就是里面包了一个Int类型,这个int类型的自增count++是线程安全的,还有拿值等等是线程安全的,由于我们在工作中开发中经常性的有那种需求,一个值所有的线程共同访问它往上递增,所以jdk专门提供了这样的一些类。
·Atomxxx类的本身方法是原子性的,但不能保证多个方法连续调用都是原子性的。
public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; }
@HotSportIntrinscCandidate public final int getAndAddInt(Object o,long offset,int delta){ int v; do{ v=getIntVolatile(o,offset); }while(!weakCompareAndSetInt(o,offset,v,v+delta)); return v; }
它内部调用的过程中就跑去了Unsafe类去了。也就是说AtomicInteger的内部调用了UnSafe这个类里面的方法CompareAndSetl(CAS)。
cas方法简单的理解的话,可以看成是
cas(V,Expected,NewValue)
V表示的是目前的值,也就是要改的值,Expected表示的是期望值,期望值就是你觉得他现在应该是多少,NewValue就是更新后的值。
如果V和Expected的值不一致的话,那么此次值变更操作将失败,说明其他线程改了这个值。那么你就可以再试一遍或者失败,这就是cas操作。
当你判断的时候发现是你的期望值,还没进行新值设定的时候,发生了改变怎么办,cas是CPU的原语支持,也就是说cas操作是cpu指令级别的操作,中间不能被打断。
ABA问题:
假如说你有一个值,我拿到的这个值是1,想把它变成2,我拿到1用cas操作,期望值是1,准备变成2,这个对象Object,在这个过程中,没有一个线程改过我肯定是可以更改的额,但是如果有一个线程在这期间把1改成了2,又改成了1,中间的值变过了,它不会影响我这个cas操作,这就是ABA问题。
这种问题的解决办法就是追加版本号,该每一次操作都追加一次修改版本号,确认期望值的时候一起确认值对应的版本号就可以了。
*CAS操作数值不需要加锁的原因是使用了Unsafe类。