专栏首页程序员备忘录CAS机制是什么?

CAS机制是什么?

因为多核CPU的存在,总是需要保障程序高性能的利用计算机的CPU资源,并要保障计算结果与预期的一致。因此常用的方式就是加锁方式。就是占用->占用结束->释放的过程,在此过程中不允许其他线程来操作已经占用的计算机资源。在单核CPU系统中,可直接通过锁住数据总线的方式达到目标。但对于多核CPU来说,其效率就太糟糕了。在多核CPU中是怎么做呐?其做法的本质还是加锁。其中CAS就是一种指令级的加锁。

  1. 什么是CAS?

CAS是compare and swap的缩写,就是比较并替换的意思。

2. CAS(比较并替换)如何保障数据一致性的?

我们设想一下,假如有2个线程。同时要操作计算机内存中的数据X=10,并将X进行加1操作。

比如线程I获取X,线程II获取X,线程II进行加1操作。此时线程I获取的X的值为10,加1之后变为11,而线程II已经将X的值变为11,因此两个线程对X的加一操作并没有达到理想中的12,而是变成了11。所以数据的一致性就得不到保障。那么面对这种情况,该如何保障数据的最终一致性?CAS的处理方式是在给X设置值得之前获取X的值,然后比较在设置值得的时候的时间段内获取到的值是否与内存中的值相同,如果相同的话,就表示X的值没有被其他线程修改,如果内存中的值与之前获取到的值不一致就表示该值已经被其他线程修改,所以该线程就抛弃之前获取到的内存中的值,并将新值作为标志。如此循环,直到计算前后从内存中获取的数据没有变化,就将其计算的结果放置到内存中。所以说CAS其实就是通过比较计算前后,所操作的数据是否发生变化来进行高并发情况下数据的一致性的。如果没有发生变化就说明当前线程的操作是安全的,否则就轮循直到所操作的数据不再变化再进行计算和赋值操作。

在此可能有人会说,那么在比较确认数据没有被其他线程修改之后设置值得时候被其他线程修改了数据怎么办?这里要注意一下CAS最终设置值得时候采用的计算机指令是原子性的,也就是说会一步走到结束。

3.CAS机制的优势和劣势是什么?

轮循导致的CPU消耗

上边说到如果所操作的数据在当下线程操作的空隙已经发生了变化,就需要不断的去轮询,直到其不再发生变化了之后才进行下一步操作。但是轮询非常消耗CPU。

只能保障数据的原子性,无法保障代码块的原子性

当多个线程操作相同的数据时,使用CAS策略能够保证该数据的原子性,但是无法保障代码块的原子性。要想实现代码块中的数据不被其他线程修改(不与预期值发生偏差),则必须使用synchronized来进行代码块级别锁了。

ABA问题

当线程I修改了X,但是线程I又将X修改为原来的值,所以线程II使用CAS策略去修改X的值时发现X并没有被修改并进行计算的过程。

线程I 获取X=10----->对X+1=11----->对X-1=10

线程II 获取X=10----------------------------------->X+1=11

时间线 t1-----------------t2------------------t3--------------t4--->

ABA问题的根源就是无法确认数据修改者的身份,因此可以通过过添加版本号的方式去解决,通过比较值再比较版本号的方式去判断其操作者,直到数据的版本号是操作者颁发的时候才有权利去修改,这样就可以解决ABA的问题。

本文分享自微信公众号 - 程序员备忘录(gh_a84f9a607848),作者:tianjl

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-05-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 线程池参数详解

    我们知道JUC提供了丰富的并发工具类,其中类似于组的结构叫做线程池。就是说我们可以将我们需要运行的线程加入到这个组内,然后通过启动线程池来执行加入到线程池的所有...

    程序员_备忘录
  • ReentrantLock源码解析

    在java编程中,经常需要多代码进行加锁来防止多线程可能引起的数据不一致。而锁的类型有公平锁和非公平锁。公平锁的意义就是按照顺序,而非公平锁则是相反的。也就是说...

    程序员_备忘录
  • Thread源码解析

    我们上学的时候都知道线程有两种方式,要么继承Thread类,要么实现runable接口。根据我们上次对线程池的分析,发现我们对Thread类的理解还比较浅显。所...

    程序员_备忘录
  • PHP到底能不能实现多线程?

    前些天帮同事查一个问题,第一次接触到了 PHP 的多线程,原以为 PHP 普遍都是单线程模型,并不适合多线程领域,花些时间翻了几个多线程的项目源码之后,发现 P...

    A梦多啦A
  • -1-5 java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait(),

    java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁  sleep()和wait()方法...

    noteless
  • 并发学习笔记13-线程基础(下)

    Volatile可以修饰字段(成员变量),就是告知程序任何对该变量的访问均需从共享内存中获取,而对它的改变必须同步刷新回共享内存,它能保证所有线程对变量访问的可...

    汐楓
  • RocketMQ 架构中的九个组件

    一、common 通用的常量枚举、基类方法或数据结构,按描述的目标来分包,通俗易懂,包名有:admin、consumer、filter、hook、message...

    heasy3
  • 多线程知识回顾

    以前看过不少JDK源码,最近回顾了一下笔记,所以在这里对几个很常见到的线程类做个记录。

    Java编程指南
  • 并发学习笔记12-线程基础(上)

    现代操作系统调度的最小单元是线程,也叫轻量级进程(Light Weight Process)。

    汐楓
  • 多线程?怎么用?

    进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。

    故里

扫码关注云+社区

领取腾讯云代金券