Talk is cheap

CAS(Compare And Swap),即比较并交换。是解决多线程并行情况下使用锁造成性能损耗的一种机制,CAS操作包含三个操作数——内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论位置V的值是否等于A, 都将返回V原有的值。

CAS的含义是”我认为V的值应该是A,如果是,那我将V的值更新为B,否则不修改并告诉V的值实际是多少“

Show you my code

在单线程环境中分别使用无锁,加锁以及cas进行十组5亿次累加运算,然后打印出平均耗时。

 /*** cas对比加锁测试** @author Jann Lee* @date 2019-11-21 0:12**/
public class CasTest {@Testpublic void test() {long times = 500_000_000;// 记录耗时List<Long> elapsedTime4NoLock = new ArrayList<>(10);List<Long> elapsedTime4Synchronized = new ArrayList<>(10);List<Long> elapsedTime4ReentrantLock = new ArrayList<>(10);List<Long> elapsedTime4Cas = new ArrayList<>(10);// 进行10组试验for (int j = 0; j < 10; j++) {// 无锁long startTime = System.currentTimeMillis();for (long i = 0; i < times; i++) {}long endTime = System.currentTimeMillis();elapsedTime4NoLock.add(endTime - startTime);// synchronized 关键字(隐式锁)startTime = endTime;for (long i = 0; i < times; ) {i = addWithSynchronized(i);}endTime = System.currentTimeMillis();elapsedTime4Synchronized.add(endTime - startTime);// ReentrantLock 显式锁startTime = endTime;ReentrantLock lock = new ReentrantLock();for (long i = 0; i < times; ) {i = addWithReentrantLock(i, lock);}endTime = System.currentTimeMillis();elapsedTime4ReentrantLock.add(endTime - startTime);// cas(AtomicLong底层是用cas实现)startTime = endTime;AtomicLong atomicLong = new AtomicLong();while (atomicLong.getAndIncrement() < times) {}endTime = System.currentTimeMillis();elapsedTime4Cas.add(endTime - startTime);}System.out.println("无锁计算耗时: " + average(elapsedTime4NoLock) + "ms");System.out.println("synchronized计算耗时: " + average(elapsedTime4Synchronized) + "ms");System.out.println("ReentrantLock计算耗时: " + average(elapsedTime4ReentrantLock) + "ms");System.out.println("cas计算耗时: " + average(elapsedTime4Cas) + "ms");}/*** synchronized加锁*/private synchronized long addWithSynchronized(long i) {i = i + 1;return i;}/*** ReentrantLock加锁*/private long addWithReentrantLock(long i, Lock lock) {lock.lock();i = i + 1;lock.unlock();return i;}/*** 计算平均耗时*/private double average(Collection<Long> collection) {return collection.stream().mapToLong(i -> i).average().orElse(0);}
}

从案例中我们可能看出在单线程环境场景下cas的性能要高于锁相关的操作。当然,在竞争比较激烈的情况下性能可能会有所下降,因为要不断的重试和回退或者放弃操作,这也是CAS的一个缺点所在,因为这些重试,回退等操作通常用开发者来实现。

CAS的实现并非是简单的代码层面控制的,而是需要硬件的支持,因此在不同的体系架构之间执行的性能差异很大。但是一个很管用的经验法则是:在大多数处理器上,在无竞争的锁获取和释放的”快速代码路径“上的开销,大约是CAS开销的两倍。

为何CAS如此优秀

硬件加持,现代大多数处理器都从硬件层面通过一些列指令实现CompareAndSwap(比较并交换)同步原语,进而使操作系统和JVM可以直接使用这些指令实现锁和并发的数据结构。我们可以简单认为,CAS是将比较和交换合成是一个原子操作

JVM对CAS的支持, 由于Java程序运行在JVM上,所以应对不同的硬件体系架构的处理则需要JVM来实现。在不支持CAS操作的硬件上,jvm将使用自旋锁来实现。

CAS的ABA问题

cas操作让我们减少了锁带来的性能损耗,同时也给我们带来了新的麻烦-ABA问题。

在线程A读取到x的值与执行CAS操作期间,线程B对x执行了两次修改,x的值从100变成200,然后再从200变回100;而后在线程A执行CAS操作过程中并未发现x发生过变化,成功修改了x的值。由于x的值100 ->200->100,所以称之为ABA的原因。

魔高一尺道高一丈,解决ABA的问题目前最常用的办法就是给数据加上“版本号”,每次修改数据时同时改变版本号即可。

Q&A

在竞争比较激烈的情况下,CAS要进行回退,重试等操作才能得到正确的结果,那么CAS一定比加锁性能要高吗?

有道无术,术可成;有术无道,止于术

欢迎大家关注Java之道公众号

好文章,我在看❤️

无锁并发的CAS为何如此优秀?相关推荐

  1. 从“惊群”的现象来看并发锁,“死锁”问题的解决方案丨Redis单线程|共享内存|无锁实现|原子操作CAS

    从"惊群"的现象来看并发锁,"死锁"问题的解决方案 视频讲解如下,点击观看: 从"惊群"的现象来看并发锁,"死锁"问题的 ...

  2. Java无锁并发详细教程

    问题提出 有如下需求,保证 account.withdraw 取款方法的线程安全 package cn.itcast;import java.util.ArrayList; import java.u ...

  3. java 无锁框架_高性能无锁并发框架 Disruptor,太强了!

    Java技术栈 www.javastack.cn 关注优质文章 Disruptor是一个开源框架,研发的初衷是为了解决高并发下队列锁的问题,最早由LMAX提出并使用,能够在无锁的情况下实现队列的并发操 ...

  4. 无锁数据结构--理解CAS、ABA、环形数组

    在分布式系统中经常会使用到共享内存,然后多个进程并行读写同一块共享内存,这样就会造成并发冲突的问题, 一般的常规做法是加锁,但是锁对性能的影响非常大. 无锁队列是一个非常经典的并行计算数据结构,它极大 ...

  5. 【java并发编程】无锁并发框架disruptor

    一.简介 Disruptor是一个高性能队列,研发的初衷是解决内部的内存队列的延迟问题,而不是分布式队列.基于Disruptor开发的系统单线程能支撑每秒600万订单. 使用场景:对延时要求很高的场景 ...

  6. Java并发编程,无锁CAS与Unsafe类及其并发包Atomic

    为什么80%的码农都做不了架构师?>>>    我们曾经详谈过有锁并发的典型代表synchronized关键字,通过该关键字可以控制并发执行过程中有且只有一个线程可以访问共享资源,其 ...

  7. Java并发编程-无锁CAS与Unsafe类及其并发包Atomic

    [版权申明]未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) http://blog.csdn.net/javazejian/article/details/72772470 出自[zejian ...

  8. 非阻塞同步算法与CAS(Compare and Swap)无锁算法

    锁(lock)的代价 锁是用来做并发最简单的方式,当然其代价也是最高的.内核态的锁的时候需要操作系统进行一次上下文切换,加锁.释放锁会导致比较多的上下文切换和调度延时,等待锁的线程会被挂起直至锁释放. ...

  9. Java CAS无锁技术深度解析

    在看AQS代码的时候,看到它很多地方调用了unsafe.compareAndSwapInt这类方法,百度了一下得知这叫CAS无锁技术. CAS原理深度分析 转自:https://blog.csdn.n ...

最新文章

  1. android自定义差值器,如何创建自定义插值器以在android中应用翻译动画
  2. jvm系列(四):jvm调优-命令大全(jps jstat jmap jhat jstack jinfo)
  3. matlab找数据的转账点,nodejs开发EOS转账服务的两种方案
  4. 原理图连线有错误提醒_拔罐方法不对=缩短生命,中医提醒,拔火罐警惕三个禁忌...
  5. shell脚本详解(六)——数组简介和排序算法
  6. 织梦响应式鲜花绿植花艺类网站模板(自适应手机端)
  7. 三点确定一个圆的计算方法
  8. Unity3D 游戏摄像机的环绕与拉近
  9. 如何搭建ftp服务器实现文件共享
  10. Java复习小游戏——“登仙长阶“【已收工】
  11. 转载:《星际争霸》星际争霸战略战术的发展和创新
  12. MySQL系列之STRAIGHT JOIN用法简介
  13. air flow空调上是什么意思_airflow空调滤芯上是什么意思
  14. 虚幻4渲染编程(光线追踪篇)【第一卷:光线追踪篇开篇综述】
  15. Snipaste - 截图贴图软件
  16. python的pandas重复值处理(duplicated()和drop_duplicates())
  17. 【机器人】工业机器人如何赋能3C制造升级?工业机器人的16项重要应用;工业机器人的11个知识问答,“业内人”必看!
  18. mask-image实现聚光灯效果
  19. php测试号推送消息失败,php 给ios推送消息 提示这个错误
  20. spring cloud config 统一配置管理

热门文章

  1. transporter上传卡正在交付_Xcode11,Transporter上传卡在——正在验证 APP - 正在通过App Store进行认证...
  2. 淮海工学院期末考试Oracle,淮海工学院大一物理期末试卷
  3. 操作系统之内存管理:3、基本分页存储管理
  4. 3-2:常见任务和主要工具之存储介质
  5. Linux下安装Octave
  6. golang map使用总结
  7. 安全测试chicklist
  8. Linux学习 命令部分
  9. Centos6.7系统环境下使用 yum install 安装mysql-community-5.7.22(史上最简)
  10. 在vue中使用express-mock搭建mock服务