java的CAS原理
what:
CAS的全称是Compare and Swap,即比较并交换。比较的是当前内存中存储的值与预期原值,交换的是新值与内存中的值。这个操作是硬件层面的指令,因此能够保证原子性。Java通过JNI(本地方法调用)来使用这个原子操作,也是乐观锁最常用的机制。
CAS操作包含三个操作数——内存位置、预期原值和新值。在执行CAS操作时,先进行Compare操作,即比较内存位置的值与预期原值是否相等,若相等,则执行Swap操作将新值放入该内存位置。若不相等,则不进行Swap操作。demo如下:
UnSafe类中的重要方法,都是native的,是调用了底层操作系统的CAS指令,如下:
where(使用场景)
在Java的concurrent包中,有一种通用的实现方式,即CAS配合volatile来实现许多高并发类。
how(缺陷的解决方案):
1、ABA问题:
value初值为A,线程1读取到预期原值为A,线程2读取到预期原值为A,线程1通过CAS操作将A更新为B,再通过一次CAS操作将值更新为A,此时线程2进行CAS操作,在比较时发现预期原值A与当前内存位置的值A相同,则进行更新,但是此时value已经被更新过了,而不是原来那个A值了,这样会产生线程安全问题。
现在也有解决方案,在Java API中有一个类为AtomicStampedReference,该类在记录预期原值的同时还会记录标志,在比较时还会比较标志。
2、自旋时间长的情况下会导致很大开销。
若JVM支持pause指令,则可以解决此问题。pause指令有两个作用,第一是延迟流水线执行指令,使得CPU不会消耗太多执行时间;第二是避免在退出循环时因内存顺序冲突而引起CPU流水线被清空。