在Java并发包中有一些并发框架也使用了自旋CAS的方式实现了原子操作,比如:LinkedTransferQueue类的Xfer方法。CAS虽然很高效的解决了原子操作,但是CAS仍然存在三大问题:ABA问题、循环时间长开销大、只能保证一个共享变量的原子操作

1.ABA问题

1.1.什么是ABA问题

因为CAS需要在操作值得时候,检查值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A、变成了B、又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但实际上却变化了。

1.2.ABA问题解决方法

1、使用版本号

ABA问题的解决思路是使用版本号,每次变量更新的时候版本号加1,那么A->B->A就会变成1A->2B->3A

2、jdk自带原子变量

从jdk1.5开始,jdk的Atomic包里就提供了一个类AtomicStampedReference来解决ABA问题,这个类中的compareAndSet方法的作用就是首先检查当前引用是否等于预期引用,并且检查当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值更新为指定的新值

/**
* 如果当前引用等于预期引用并且当前标志等于预期标志
* 则以原子方式将该引用和该标志的值设置为给定新值
*
* @param expectedReference 预期引用值
* @param newReference 新的引用值
* @param expectedStamp 预期标记值
* @param newStamp 新标记值
* @return {@code true} if successful
*/
public boolean compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
Pair<V> current = pair;
return
#预期引用==当前引用
expectedReference == current.reference &&
#预期标志==当前标志
expectedStamp == current.stamp &&
#新引用==当前引用 并且 新标志==当前标志
((newReference == current.reference &&
newStamp == current.stamp) ||
#原子更新值
casPair(current, Pair.of(newReference, newStamp)));
}

2.循环时间长开销大

自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销。如果jvm能支持处理器提供的pause指令,那么效率会有一定的提升。pause指令有两个作用:

第一,它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零。

第二,它可以避免在退出循环的时候因内存顺序冲突(Memory Order Violation)而引起CPU流水线被清空(CPU Pipeline Flush),从而提高CPU的执行效率。

3.只能保证一个共享变量的原子操作

当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁。还有一个方法,就是把多个共享变量合并成一个共享变量来操作。比如,有两个共享变量i=2,j=a合并一下ij=2a,然后用CAS来操作ij。从java1.5开始,JDK提供了AtomicReference类来保证引用对象之间的原子性,就可以把多个变量放在一个对象里来进行CAS操作。

Java并发之CAS的三大问题的更多相关文章

  1. Java并发之CAS与AQS简介

    1,什么是CAS CAS(Compare And Swap),即比较并交换.是解决多线程并行情况下使用锁造成性能损耗的一种机制,CAS操作包含三个操作数——内存位置(V).预期原值(A)和新值(B). ...

  2. java并发之CAS详解

    前言 在高并发的应用当中,最关键的问题就是对共享变量的安全访问,通常我们都是通过加锁的方式,比如说synchronized.Lock来保证原子性,或者在某些应用当中,用voliate来保证变量的可见性 ...

  3. Java中的CAS原理

    前言:在对AQS框架进行分析的过程中发现了很多CAS操作,因此有必要对CAS进行一个梳理,也便更清楚的了解其原理. 1.CAS是什么 CAS,是compare and swap的缩写,中文含义:比较交 ...

  4. 深入理解Java并发之synchronized实现原理

    深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解Java类加载器(ClassLoader) 深入 ...

  5. java并发之hashmap源码

    在上篇博客中分析了hashmap的用法,详情查看java并发之hashmap 本篇博客重点分析下hashmap的源码(基于JDK1.8) 一.成员变量 HashMap有以下主要的成员变量 /** * ...

  6. JAVA并发编程: CAS和AQS

       版权声明:本文为博主原创文章,转载请注明出处 https://blog.csdn.net/u010862794/article/details/72892300 说起JAVA并发编程,就不得不聊 ...

  7. 《提升能力,涨薪可待》—Java并发之Synchronized

    Synchronized简介 线程安全是并发编程中的至关重要的,造成线程安全问题的主要原因: 临界资源, 存在共享数据 多线程共同操作共享数据 而Java关键字synchronized,为多线程场景下 ...

  8. Java并发之AQS原理解读(二)

    上一篇: Java并发之AQS原理解读(一) 前言 本文从源码角度分析AQS独占锁工作原理,并介绍ReentranLock如何应用. 独占锁工作原理 独占锁即每次只有一个线程可以获得同一个锁资源. 获 ...

  9. Java并发之AQS原理解读(一)

    前言 本文简要介绍AQS以及其中两个重要概念:state和Node. AQS 抽象队列同步器AQS是java.util.concurrent.locks包下比较核心的类之一,包括AbstractQue ...

随机推荐

  1. centos 配置rsync+inotify数据实时同步

    何为rsync? 定义: rsync是一个开源的快速备份工具,可以在不同主机之间镜像同步整个目录树,支持增量备份,保持链接和权限,非常适用于异地备份 何为源端和发起端? 在远程同步过程中,负责发起rs ...

  2. 【Git的基本操作三】基本操作命令

    基本操作 (1) 状态查看操作 git status 作用:查看工作区.暂存区状态 (2) 添加操作 git add [filename] 作用:将工作区文件的 添加/修改,添加到暂存区 (3) 提交 ...

  3. string字符串长度和字节长度问题

    string str = "abcdef 安安安"; int i = str.Length; byte[] bt = System.Text.Encoding.Default.Ge ...

  4. 1-10000以内的完数(js)

    //1-10000以内的完数 //完数:因子之和相加等于这个数 //例如:6的因子为1,2,3:1+2+3=6 // 6 // 28 // 496 // 8128 let sum = 0, i, j; ...

  5. head pose estimation

    opencv:帖子中介绍了算法原理和opencv估计姿态的代码 https://www.learnopencv.com/head-pose-estimation-using-opencv-and-dl ...

  6. 【转】sscanf函数用法实例

    sscanf() - 从一个字符串中读进与指定格式相符的数据.  函数原型:  Int sscanf( string str, string fmt, mixed var1, mixed var2 . ...

  7. Linux下kafka集群搭建

    环境准备 zookeeper集群环境 kafka是依赖于zookeeper注册中心的一款分布式消息对列,所以需要有zookeeper单机或者集群环境. 三台服务器: 172.16.18.198 k8s ...

  8. 使用metamask钱包

    一.安装火狐浏览器metamask插件 打开火狐浏览器的附件组件,搜索metamask 点击第一个 点击“添加到Firefox” 添加成功后,浏览器右上角有一个狐狸标志 点击这个标志,打开插件 二.创 ...

  9. 牛客小白月赛12 I 华华和月月逛公园 (tarjian 求桥)

    链接:https://ac.nowcoder.com/acm/contest/392/I 来源:牛客网 华华和月月逛公园 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K, ...

  10. java8学习之BiFunction函数式接口实例演示&Predicate函数式接口详解

    BiFunction函数式接口: 在上次中已经对BiFunction接口进行了初步的认识,这里对它进一步学习,这里打算新建一个Person实体,然后新建若干个Person的实例存放在集合中,最后再根据 ...