技术类 -- CAS
1.CAS是什么
Compare And Swap
CAS是一种无锁化编程技术,它常用于在并发编程中保证线程的安全问题
CAS通过比较预期值和内存中的值是否匹配来决定要不要更新内存数据,通过使用CAS可以减少锁的使用,从而避免锁带来的性能下降、死锁等问题,实现无锁化编程,而且CAS是一个原子操作,不会被打断。
关于为什么在某些场景下会使用无锁化编程,详情可以看看这篇《Java中的锁机制》
tips:CAS是java.util.concurrent.atomic包提供的,concurrent这个包提供的内容都是线程安全的
2.CAS的实现
Java中,CAS通过java.util.concurrent.atomic包中提供的类实现,如atomicInteger、atomicReference
3.CAS的缺点以及优化
3.1 CAS的局限性
-
ABA问题
由于CAS比较的只是预期和内存中值是否相等,而ABA问题顾名思义,开始是A,中间变为了B,之后又一个线程修改为了A,那么从结果出发,预期和内存一致,可以修改,但是这种情况下我们就会产生逻辑上的问题 -- 即没有线程进行过修改
如果你觉得这么讲,好像也ok,因为结果是一样的,那么假设,在一个银行账户取款的场景中,如果一个线程读取账户余额为1000元(A),然后账户被另一个线程修改为500元(B),接着又被修改回1000元(A),如果原始线程没有注意到中间的变化,它可能会错误地认为账户余额仍然是1000元,并继续执行取款操作,导致实际余额低于预期
-
自旋等待问题
CAS如果更新失败是不会返回的,而是会不断地重试,直到操作完成
说到这里,问题就显而易见了,如果我们的更新操作一直无法成功,那么CAS就会一直自旋浪费性能,因为他是一直占用CPU资源空转的,尤其是锁竞争激烈的环境或者CAS成功率低下的场景
3.2 优化
针对ABA问题,我们可以想办法给每次修改再做一个标识,通过添加版本号、时间戳等方式,每次修改不仅要比较内存的值和预期值,还要比较版本号和时间戳是否发生了变化,这样就可以避免ABA问题的出现
针对自旋等待问题,一些编程语言采用了一些自适应自旋的机制,例如,Java HotSpot虚拟机就采用了自适应自旋策略,根据前一次自旋的成功或失败情况来调整自旋的次数。如果自旋成功,虚拟机可能会增加自旋的次数;如果自旋失败,虚拟机会减少自旋次数,以避免长时间无效的自旋消耗CPU资源