前文《Java面试必考问题:如何理解volatile关键字? 》介绍了 volatile 关键字,可以保证多线程的可见性和有序性,但是不能保证原子性。要保证多线程操作的原子性,除了可以使用 synchronized 关键字,另外还可以通过CAS算法。
在JDK1.5以后的 java.util.concurrent.atomic 包(JUC)下,提供了大量的原子变量类型,包括AtomicBoolean,AtomicInteger,AtomicLong等,其内部都是使用CAS算法。
什么是CAS
CAS(Compare-and-Swap),是一种系统原语,是不可分割的操作系统指令。
CAS包含了3个操作数:
要操作的内存值 V
旧的预期值 A
要修改的新值 B
CAS算法流程
当且仅当 V == A 时, 内存值更新为新值 B; 否则,不会执行任何操作。CAS更新不成功,则开始自旋,重复刚才的过程。
在整个过程中,是不需要在软件层面加锁的,这是一种乐观锁的策略。只要内存值没有发生变化,那么相信在这次修改之前,没有其它线程去动过它。synchronized锁是悲观锁策略。
CAS的底层实现
底层硬件通过将 CAS 里的多个操作在处理器指令层面上实现,通过一条处理器指令保证了原子性操作,现代多核处理器支持的原子性操作中通常都包括CAS功能。下图是CAS操作的函数调用链,我们看一下Java的CAS原子操作是如何在处理器指令层面实现的。
在IA64,x86 指令集中有 cmpxchg 指令完成 CAS 功能,在 sparc-TSO 也有 casa 指令实现,而在 ARM 和 PowerPC 架构下,则需要使用 ldrex/strex 一对指令来完成 LL/SC 的功能。