javacas算法(javacasaba问题解决)
导语:Java面试必考问题:如何解决CAS算法的ABA问题
前文《Java面试必考问题:CAS如何保证原子性? 》中介绍过CAS算法。JDK5增加JUC包(java.util.concurrent),其中Atomic原子类都使用了CAS操作。这些CAS操作基于Unsafe类中的native方法实现。
在资源竞争少时,CAS基于硬件实现,不进入内核,不切换线程,操作自旋几率小,相比synchronized,CAS有更高的性能。但CAS也有一些问题:
ABA问题自旋开销只能保证一个共享变量的原子操作CAS
如果CAS操作自旋长时间不成功会给CPU带来非常大的执行开销。
另外,当操作涉及多个共享变量时,CAS操作无效。这时我们可以考虑用AtomicReference引用类型来封装多个字段,来保证多变量操作的原子性。
ABA问题
ABA问题
上图展示了ABA问题的出现:变量 var 初次读时是 A 值,被赋值时也是 A 值,但期间变量被其他线程一度赋值成B值,后来又改回 A 值,CAS会误认为变量 var 从没被修改过。这样就语义就违背了真实情况。
那么如何解决ABA问题?
通过加入版本号或者其他标识,来识别变量是否被修改过,避免ABA问题
我们可以通过加一个版本号 version 来解决ABA问题。对于所有使用变量 var 的线程,如果修改了变量的值,都需要将对应的版本号 version 进行递增。CAS在进行变量前后值的对比时,除了要对比原来的变量值,还要对比版本号的值是否一样,这样就解决了ABA问题。
乐观锁的实现机制主要包括版本号机制(给数据加一个版本号,数据被修改版本号会加一,更新时读取版本号,若读取到的版本号和之前一致才更新,否则驳回)。
JUC包的解决方案
在JUC包中提供了AtomicStampedReference 和 AtomicMarckableReference 类,这两个类具有监测ABA问题的能力。其中的 compareAndSet() 方法首先检查当前对象值是否等于预期值,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将对象值和标志的值都更新为新值。
AtomicStampedReference 在构造方法中加入了类似时间戳(stamp)的字段作为标识,采用自增 int 作为 stamp,在stamp不重复的前提下可以解决ABA问题,AtomicStampedReference 可以获知对象值被更改了几次。
如果我们不需要知道对象值被更改几次,而仅需要知道是否被更改过的话,那么可以使用AtomicMarkableReference,这个类用 boolean变量 表示变量是否被更改过。
我会持续更新关于物联网、云原生以及数字科技方面的文章,用简单的语言描述复杂的技术,也会偶尔发表一下对IT产业的看法,欢迎大家关注,谢谢。
免责声明:本站部份内容由优秀作者和原创用户编辑投稿,本站仅提供存储服务,不拥有所有权,不承担法律责任。若涉嫌侵权/违法的,请反馈,一经查实立刻删除内容。本文内容由快快网络小莉创作整理编辑!