15. Java的 CAS 操作原理

1. 前言

本节内容主要是对 CAS 操作原理进行讲解,由于 CAS 涉及到了并发编程包的使用,本节课程只对 CAS 的原理问题进行讲解,有助于同学后续对并发编程工具使用的学习。本节具体内容点如下:

  • 了解 CAS 的概念,这是本节内容的基础知识;
  • 了解 CAS 诞生的背景,能够更好地理解 CAS,这是本节的基础知识;
  • 了解 CAS 操作诞生的意义,这也是 CAS 操作的作用所在;
  • 了解 CAS 的操作原理,这也是本节内容的核心知识点,其他知识点都是围绕这一知识点展开的;
  • 了解 CAS 中常见的 ABA 问题,这是本节内容的重点。

2. 什么是 CAS

概念:CAS 是 CompareAndSwap 的简称,是一种用于在多线程环境下实现同步功能的机制。

从字面上理解就是比较并更新。简单来说,从某一内存上取值 V,和预期值 A 进行比较,如果内存值 V 和预期值 A 的结果相等,那么我们就把新值 B 更新到内存,如果不相等,那么就重复上述操作直到成功为止。

3. CAS 诞生的背景

synchronized 时代:在多线程中为了保持数据的准确性,避免多个线程同时操作某个变量,很多情况下利用关键字 synchronized 实现同步锁。

使用 synchronized 关键字可以使操作的线程排队等待运行,可以说是一种悲观策略,认为线程会修改数据,所以开始就把持有锁的线程锁住,其他线程只能是挂起状态,等待锁的释放,所以同步锁带来了效率问题。

synchronized 时代效率问题:在线程执行的时候,获得锁的线程在运行,其他被挂起的线程只能等待着持有锁的线程释放锁才有机会运行,在效率上都浪费在等待上。

在很多的线程切换的时候,由于有同步锁,就要涉及到锁的释放,加锁,这又是一个很大的时间开销。

volatile 时代:与锁(阻塞机制)的方式相比有一种更有效地方法,非阻塞机制,同步锁带来了线程执行时候之间的阻塞,而这种非阻塞机制在多个线程竞争同一个数据的时候不会发生阻塞的情况,这样在时间上就可以节省出很多的时间。

我们会想到用 volatile,使用 volatile 不会造成阻塞,volatile 保证了线程之间的内存可见性和程序执行的有序性可以说已经很好的解决了上面的问题。

volatile 时代原子操作问题:一个很重要的问题就是,volatile 不能保证原子性,对于复合操作,例如 i++ 这样的程序包含三个原子操作:取值,增加,赋值。

4. CAS 操作诞生的意义

意义:从上边 CAS 操作诞生的背景所说的,CAS(Compare And Swap 比较和交换)解决了 volatile 不能保证原子性的问题。从而 CAS 操作即能够解决锁的效率问题,也能够保证操作的原子性。

Tips:在 JDK1.5 新增的 java.util.concurrent (JUC java 并发工具包) 就是建立在 CAS 之上的。相比于 synchronized 这种堵塞算法, CAS 是非堵塞算法的一种常见实现。所以 JUC 在性能上有了很大的提升。

5. CAS 操作原理

CAS 主要包含三个操作数,内存位置 V,进行比较的原值 A,和新值 B。

当位置 V 的值与 A 相等时,CAS 才会通过原子方式用新值 B 来更新 V,否则不会进行任何操作。无论位置 V 的值是否等于 A,都将返回 V 原有的值。

上面说到了同步锁是一种悲观策略,CAS 是一种乐观策略,每次都开放自己,不用担心其他线程会修改变量等数据,如果其他线程修改了数据,那么 CAS 会检测到并利用算法重新计算。

CAS 也是同时允许一个线程修改变量,其他的线程试图修改都将失败,但是相比于同步锁,CAS 对于失败的线程不会将他们挂起,他们下次仍可以参加竞争,这也就是非阻塞机制的特点。

6. ABA 问题

ABA 问题描述

  • 假设有两个线程,线程 1 和线程 2,线程 1 工作时间需要 10 秒,线程 2 工作需要 2 秒;
  • 主内存值为 A,第一轮线程 1 和线程 2 都把 A 拿到自己的工作内存;
  • 第 2 秒,线程 2 开始执行,线程 2 工作完成把 A 改成了 B ;
  • 第 4 秒,线程 2 把 B 又改成了 A,然后就线程 2 进入休眠状态;
  • 第 10 秒,线程 1 工作完成,看到期望为 A 真实值也是 A 认为没有人动过,其实 A 已经经过了修改,只不过又改了回去,然后线程 1 进行 CAS 操作。

ABA 问题解决:为了解决这个问题,在每次进行操作的时候加上一个版本号或者是时间戳即可。

7. 小结

本节内容的核心知识点即了解 CAS 的操作原理,其他知识点都是围绕这一知识点展开的,对于 CAS 中所引发的 ABA 问题以及该问题的解决方式为本节内容重点。需要对这两点进行着重掌握。

  • 16
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Java CAS(Compare And Swap,比较并交换)是一种常用于多线程编程的原子操作。其主要作用是在多线程环境下保证变量的原子性和一致性,解决多线程竞争条件下的并发问题。 Java CAS原理是通过比较内存中的值与期望值是否相等来确定是否进行交换,其核心思想是利用硬件的原子性操作来实现并发的同步,而不需要使用锁(synchronized)等机制。 具体来说,CAS操作包含三个参数:内存地址、旧的预期值和新的值。 1. 首先,CAS会将当前内存地址中的值与旧的预期值进行比较,如果相等,则说明内存中的值未被其他线程修改。 2. 然后,CAS会使用新的值来更新内存地址中的值,完成交换操作。 3. 最后,CAS会返回旧的预期值,可以通过返回值进行判断操作是否成功。 需要注意的是,CAS是一种乐观的并发控制方式,它不会阻塞线程,而是通过不断重试的方式来保证操作的原子性。如果CAS操作失败,那么线程会重新读取内存中的值,并重新尝试进行CAS操作,直到成功为止。 然而,CAS也存在一些问题。首先,CAS需要频繁地读取和写入内存,这对内存带宽的要求较高;其次,由于CAS操作是无锁的,因此存在ABA问题,即在操作过程中,如果其他线程修改了预期值两次并恢复为原来的值,CAS操作无法察觉。 总之,Java CAS作为一种基于硬件支持的原子操作,可以在多线程环境下实现高效的同步控制,然而它也需要开发人员自行处理ABA问题以及确保程序的正确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

红薯不甜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值