一 . 概述
我们知道加锁会对多线程的并发有影响,那么我们是否有无锁的方式保证线程的安全性呢?有的,就是CAS方式.
CAS的核心就是乐观的尝试,将线程的阻塞变成了线程的尝试,认为即使在不断尝试的代价也比阻塞后唤醒的代价要小.
二 CAS
CAS到底是什么呢? 其实就是一个JVM的指令,其中这个指令的执行是原子性的,也就是说不会被打断.
我们看下AtomicInter的原子实现:
public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }
我们看到使用了unsafe完成了CAS操作,CAS代表的就是比较并且更新(交换).
当现在的值等于期待值就会更新并且返回ture,
不等于就会返回false,并且不会更新.
public final int getAndUpdate(IntUnaryOperator updateFunction) { int prev, next; do { prev = get(); next = updateFunction.applyAsInt(prev); } while (!compareAndSet(prev, next)); return prev; }
我们看上述的JDK的实现,使用了一个while循环不断试探是否是线程安全的.
我们知道while体内的操作可能不是安全的,也就是会发生修改修改,那么现在的值就和期待值不一致,那么CAS保证不去更新.
循环就会再次尝试,知道成功为止.
通过这种尝试的方式保证操作是线程安全的.
三 .ABA问题
我们知道,CAS不保证循环体的过程,但是保证结果是正确的,这也就是说循环体内
可能发生了一个自减操作,然后又做出了一个自增操作,这种情况下,期待值和实际值确实是一致的,但是不能保证原子性了.
问题解决:
解决的方式很简单,我们在原始的CAS之上加上一个时间戳,时间戳可以保证两次操作之间不应该有其它的操作.
为此,出现了AtomicStampedReference这样的类可以保证线程安全.
原文:https://www.cnblogs.com/trekxu/p/8996782.html