为了把关于线程相关的内容搞清楚,在synchronized一节中有提到CAS这个操作
一、什么是CAS?
CAS,compare and swap的缩写,中文翻译成比较并交换。JDK提供的非阻塞原子性操作,它通过硬件保证了更新操作的原子性。它允许多线程非阻塞地对共享资源进行修改,但是同一时刻只有一个线程可以修改,其他线程并不会阻塞而是重新尝试。
CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值 。否则,处理器不做任何操作。
二、为什么会有CAS?
一般乐观锁采取的策略。在Java中使用锁不好的地方就是当一个线程没有获得锁,就会导致线程的上下文切换,导致重新调度与开销。而volatile只能保证有序性和可见性,并不能保证原子性。CAS操作保证了原子性。
三、CAS详解
CAS,比较和交换,从语义上是两步操作,但实际上一条CPU指令就能完成。这说明,他是一个原子性操作,要么全做,要么全不做。
JDK的Unsafe类提供了compareAndSwap方法,boolean compareAndSwapLong(Object obj,Long valueOffset,long expect,long update);
参数:对象的内存地址,偏移值,期望的旧值,期望的新值
如果对象 obj中内存偏移量为 valueOffset的变量值为 expect,则使用新的值 update替换旧值 expect。这是处理器提供的一个原子性操作。
CAS经典问题:ABA问题
假如线程1使用CAS修改初始值为A的变量X(X=A),那么线程1首先会获取当前变量X的值(A),然后使用CAS操作尝试修改X的值为B,如果使用CAS修改成功了,那么程序运行一定是正常的吗?其实未必,这是因为有可能在线程1获取到变量X的值A后,在执行CAS之前,线程2使用了CAS修改了变量X值为B,然后又使用了CAS操作使得变量X值为A,虽然线程A执行了CAS操作时X=A,但是这个A已经不是线程1获取到的A了。这就是ABA问题。ABA问题的产生是因为变量的状态值产生了环形转换,就是变量值可以从A到B,也可以B到A,如果变量的值只能朝着一个方向转换,例如A到B,B到C,不构成环路,就不会存在这个问题。JDK中的AtomicStampedReference类给每个变量的状态值都配备了一个时间戳,从而避免了ABA问题。或者是使用版本号,一个数据一个版本号,版本号不同数据值相同,也不会进行修改。
ABA问题会导致什么后果?
对于像库存数据的变化,通常来说,不会对结果造成影响。但是对于栈来说就会有影响。
再看一个堆栈操作的例子:
并发1(上):读取栈顶的元素为“A1”
并发2:进行了2次出栈
并发3:又进行了1次出栈
并发1(下):实施CAS乐观锁,发现栈顶还是“A1”,于是修改为A2
此时会出现系统错误,因为此“A1”非彼“A1”
标签:ABA,java,变量,CAS,修改,线程,操作 From: https://www.cnblogs.com/freewsf/p/17163485.html