cas算法是什么_对算法的认识

cas算法是什么_对算法的认识应用原子操作类,例如AtomicInteger,AtomicBoolean …适用于并发量较小,多cpu情况下;Java中有许多线程安全类,比如线程安全的集合类。从Java5开始,在java.util.concurrent包下提供了大量支持高效并发访问的集合接口和实现类。如:ConcurrentMap、ConcurrentLinkedQueue等线程安全集合。引入问题那么问题来了,这些线程安全类的底层是怎么保证线程安全的,你可能会想到是不是使用同步代码锁synchronized?引入概念这些线

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

应用

原子操作类,例如AtomicInteger,AtomicBoolean …
适用于并发量较小,多cpu情况下;
Java中有许多线程安全类,比如线程安全的集合类。从Java5开始,在java.util.concurrent包下提供了大量支持高效并发访问的集合接口和实现类。如:ConcurrentMap、ConcurrentLinkedQueue等线程安全集合。
引入问题
那么问题来了,这些线程安全类的底层是怎么保证线程安全的,你可能会想到是不是使用同步代码锁synchronized?
引入概念
这些线程安全类底层实现使用一种称为CAS的算法,(Compare And Swap)比较交换。其实现方式是基于硬件平台的汇编指令,在intel的CPU中,使用的是cmpxchg指令,也就是说CAS是靠硬件实现的,从而在硬件层面提升效率。
乐观锁,总是认为是线程安全的,不怕别的线程修改变量,如果修改了我就再重新尝试。
悲观锁:总是认为线程不安全,不管什么情况都进行加锁,要是获取锁失败,就阻塞。

优点
这个算法相对synchronized是比较“乐观的”,它不会像synchronized一样,当一个线程访问共享数据的时候,别的线程都在阻塞。synchronized不管是否有线程冲突都会进行加锁。由于CAS是非阻塞的,它死锁问题天生免疫,并且线程间的相互影响也非常小,更重要的是,使用无锁的方式完全没有锁竞争带来的系统开销,也没有线程间频繁调度带来的开销,所以它要比锁的方式拥有更优越的性能。

实现思想
在线程开启的时候,会从主存中给每个线程拷贝一个变量副本到线程各自的运行环境中,CAS算法中包含三个参数(V,E,N),V表示要更新的变量(也就是从主存中拷贝过来的值)、E表示预期的值、N表示新值。
在这里插入图片描述

实现过程
假如现在有两个线程t1,t2,,他们各自的运行环境中都有共享变量的副本V1、V2,预期值E1、E2,预期主存中的值还没有被改变,假设现在在并发环境,并且t1先拿到了执行权限,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次发起尝试,然后t1比较预期值E1和主存中的V,发现E1=V,说明预期值是正确的,执行N1=V1+1,并将N1的值传入主存。这时候贮存中的V=21,然后t2又紧接着拿到了执行权,比较E2和主存V的值,由于V已经被t1改为21,所以E2!=V,t2线程将主存中已经改变的值更新到自己的副本中,再发起重试;直到预期值等于主存中的值,说明没有别的线程对旧值进行修改,继续执行代码,退出;

底层原理
CPU实现原理指令有两种方式:

通过总线锁定来保证原子性
总线锁定其实就是处理器使用了总线锁,所谓总线锁就是使用处理器提供的一个 LOCK# 信号,当一个处理器在总线上输出此信号时,其他处理器的请求将被阻塞住,那么该处理器可以独占共享内存。但是该方法成本太大。因此有了下面的方式。

通过缓存锁来保证
所谓缓存锁定是指内存区域如果被缓存在处理器的缓存行中,并且在Lock操作期间被锁定,那么当它执行锁操作写回内存时,处理器不在总线上声言LOCK#信号,而是修改内部地址,并允许它的缓存一致性机制来保证操作的原子性,因为缓存一致性机制会阻止同时修改两个以上处理器缓存的内存区域数据,当其他处理器回写已被锁定的缓存行的数据时,会使缓存行无效。

有两种情况下处理器不会使用缓存锁定:

当操作的数据不能被缓存在处理器内部,或操作的数据跨多个缓存行时,则处理器会调用总总线锁定;
有些处理器不支持缓存锁定,对于Intel486和pentinum处理器,就是锁定的内存区域在处理器的缓存航也会调用总线锁定。
CAS源码分析

以AtomicInteger为例:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

Unsafe是CAS的核心类,Java无法直接访问底层操作系统,而是通过本地native方法来访问,尽管如此,JVM还是开了一个后门:Unsafe它提供了硬件级别的原子操作。
在这里插入图片描述
在这里插入图片描述

在底层调用汇编指令cmpxchg指令,这是一条汇编指令,所以CPU一次通过,是原子操作。

CAS缺点

循环时间太长;
只能保证一个共享变量原子操作;
会出现ABA问题;
结论
其实就是拿副本中的预期值与主存中的值作比较,如果相等就继续替换新值,如果不相等就说明主存中的值已经被别的线程修改,就继续重试;

CAS(比较并交换)是CPU指令级的操作,只有一步原子操作,所以非常快。而且CAS避免了请求操作系统来裁定锁的问题,不用麻烦操作系统,直接在CPU内部就搞定了

转载自添加链接描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/168681.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • mysql数据库日志存储位置_MySQL数据库之mysql日志文件在哪 如何修改MySQL日志文件位置…「建议收藏」

    mysql数据库日志存储位置_MySQL数据库之mysql日志文件在哪 如何修改MySQL日志文件位置…「建议收藏」本文主要向大家介绍了MySQL数据库之mysql日志文件在哪如何修改MySQL日志文件位置,通过具体的内容向大家展现,希望对大家学习MySQL数据库有所帮助。MySQL日志文件相信大家都有很多的了解,MySQL日志文件一般在:/var/log/mysqld.log,下面就教您修改MySQL日志文件位置的方法,供您参考。今天需要改MySQL日志文件的位置,发现在/etc/my.cnf中怎么也改不…

    2022年10月14日
    3
  • shell中的if判断语句怎么写_shell编程if语句格式

    shell中的if判断语句怎么写_shell编程if语句格式文章目录1.判断语句介绍-if2.if…else语句(一个条件两个判断结果)3.if…elif…else语句(多条件多个判断结果)4.if嵌套if语句5.if和命令的操作1.判断语句介绍-if当编写程序时,需要对上一步执行代码是否执行成功进行判断,可以用if语句进行判断。通过查看if语句执行的判断结果查看代码是否执行成功当满足条件的代码块中有exit,表示退出脚本执行注意:注意if和[]有空格,[]和condition也有空格隔开,运算符也有空格。缩进可以任意缩进单

    2022年8月18日
    8
  • VRRP虚IP漂移

    VRRP虚IP漂移

    2020年11月20日
    265
  • Redis主从复制原理_数据库主从复制的原理

    Redis主从复制原理_数据库主从复制的原理十八岁男孩爆肝Redis极品文章,必须三连奥里给爆赞

    2022年8月13日
    4
  • Python:Flask使用jsonify格式化时间

    Python:Flask使用jsonify格式化时间代码如下#-*-coding:utf-8-*-fromdatetimeimportdatetime,datefromflask.jsonimportJSONEncoderclassCustomJSONEncoder(JSONEncoder):defdefault(self,obj):ifisinstance(obj,datetime):returnobj.strftime(‘%Y-%m-%d%H:%M:%

    2022年5月20日
    77
  • TimeSpan用法详解

    TimeSpan用法详解1 DateTime 值类型代表了一个从公元 0001 年 1 月 1 日 0 点 0 分 0 秒到公元 9999 年 12 月 31 日 23 点 59 分 59 秒之间的具体日期时刻 因此 你可以用 DateTime 值类型来描述任何在想象范围之内的时间 一个 DateTime 值代表了一个具体的时刻 2 TimeSpan 值包含了许多属性与方法 用于访问或处理一个 TimeSpan 值下面的列表涵盖了其中的一部分 Add 与另一个 TimeSpa

    2025年6月29日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号