一、CAS是什么
比较并交换(CompareAndSwap)。
JDK1.5之前,Java语言靠synchronized关键字保证同步,是一种独占锁,也是悲观锁。JDK1.5 增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronized同步锁的一种乐观锁,CAS是一种无锁算法。
二、CAS底层原理
2.1 Unsafe类
Unsafe类时CAS的核心类,由于Java方法无法直接访问底层系统,需要通过本地(native)方法来访问,Unsafe相当于一个后门,基于该类可以直接操作一个特定内存的数据。Unsafe类位于sun.misc包中,其内部方法操作可以像C的指针一样直接操作内存,因为Java中CAS操作的执行依赖于Unsafe类的方法。
注意,Unsafe类中的所有方法都是native修饰的,也就是说Unsafe类中的方法都是直接操作操作系统底层资源执行相应任务。
2.2 CAS与Unsafe
CAS是一条并发原语,体现在Java语言中就是sun.misc.Unsafe类中的各个方法。调用Unsafe类中的CAS方法,JVM会帮我们实现出CAS汇编指令。这是一种完全依赖于硬件的功能,通过它实现了原子操作。
再次强调,由于CAS是一种系统原语,原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断。也就是说,CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。
2.3 atomicInteger.getAndIncrement();
2.4 unsafe.getAndAddInt()
参数介绍:
var1 AtomicInteger对象本身。
var2 该对象值的引用地址。
var4 需要变动的数量。
var5 用var1和var2找出的主内存中真实的值。
用该对象当前值与var5比较。
如果相同,更新var5+var4并且返回true。
如果不相同,继续取值然后比较,直至更新完成。
假设线程A和线程B两个线程同时执行getAndAddInt操作(分别跑在不同CPU上) |
2.5 CAS的缺点
- 循环时间长,开销很大
unsafe.getAndAddInt方法执行时,有个do...while,如果CAS失败,会一直尝试。如果CAS长时间不成功,可能会给CPU带来很大的开销 - 只能保证一个共享变量的原子操作
当对一个共享变量执行操作时,我们可以循环CAS的方式来保证原子操作;但是当多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁来保证原子性。 - 引来ABA问题