栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JUC-CAS机制

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JUC-CAS机制

文章目录
    • CAS(比较并交换)
      • CAS的实现原理
      • 代码实例CAS:
      • CAS缺陷
      • CAS VS synchronized

CAS(比较并交换)

CAS 全称是 compare and swap,是一种用于在多线程环境下实现同步功能的机制。CAS 操作包含三个操作数 – 内存位置、预期数值和新值。CAS 的实现逻辑是将内存位置处的数值与预期数值想比较,若相等,则将内存位置处的值替换为新值。若不相等,则不做任何操作.
是CPU硬件级别提供的功能。java.util.concurrent包中使用该技术实现乐观锁,换句话说java.util.concurrent包是完全建立在CAS之上,AQS同步组件、Atomic原子类操作等都是基于CAS实现的。CAS在JUC包中所处的位置如图:

CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。

java中具体的CAS操作是由类sun.misc.Unsafe来负责的。Unsafe类提供了硬件级别的原子操作(即native方法),Java使用native方法来间接访问操作系统底层(如系统硬件等),扩展Java程序的功能。native具体方法使用C++实现。sun.misc.Unsafe提供了三个CAS操作,从方法名即可看出,分别针对Object类型、int类型和long类型。

Java平台有个用户和本地C代码进行互操作的API,称为Java Native Interface (Java本地接口)。


参数var1:表示要操作的对象
参数var2:表示要操作对象属性地址的偏移量
参数var4:表示需要修改数据的期望值
参数var5:表示需要修改为的新值

CAS的实现原理

CAS通过调用JNI的代码来实现,JNI:Java Native Interface ,允许Java调用其他语言,而compareAndSwapxxx系列的方法就是借助“C语言”来调用CPU底层的指令实现的,
以常用的Inter x86平台来说,最终能映射到CPU的指令为“cmpxchg”,这是一个原子指令,CPU执行此命令时,实现比较并替换的操作

cmpxchg怎么保证多线程下的线程安全

  1. 系统底层进行CAS操作的时候,会判断当前系统是否为多核心系统,如果是,就给“总线”加锁,只有一个线程会进行CAS操作,CAS的原子性是平台级别的!!!
代码实例CAS:

具体方法:

compareAndSet(int expect, int update)
如果当前值 ==为预期值,则将该值原子设置为给定的更新值。

get()
获取当前值。

public class CASDemo {
    public static void main(String[] args) {
		//设置初始值为1.
        AtomicInteger atomicInteger = new AtomicInteger(1);
        //CAS--比较并交换
        //如果期望值找到了就更新,负责不更新
        //CAS 是CPU的并发原语
        System.out.println(atomicInteger.compareAndSet(1, 2));
        System.out.println(atomicInteger.get());
        System.out.println(atomicInteger.compareAndSet(1, 2));
        System.out.println(atomicInteger.get());
    }
}

结果:由1变为2后,内存中的数据为2,再由1变2时变换失败。

true
2
false
2

上文说过CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B,但是仔细看Unsafe提供的CAS操作有4个操作数,这是因为Unsafe提供的CAS操作具体实现是使用C++来实现的,C++可以直接操作内存,效提升操作效率,直接用对象和字段偏移量来获取内存值V,第一个参数是要修改field所在的对象 ,第二个参数是对象中需要修改的field的偏移量(field偏移量这个参数所代表的意思是某个字段相对Java对象的“起始地址”的偏移量,Unsafe提供了一个方法objectFieldOffset(Field var1)来获取这个参数值,第三个参数就是旧的预期值A,第四个参数是要修改的新值B。

unsafe


CAS缺陷

①循环时间长导致CPU负载高

CAS操作一般和循环搭配使用(即我们所说的自旋CAS),失败了就会一直执行,直到修改成功才会退出循环。如果在某些并发量较大的情况下,变量的值始终被别的线程修改,自旋CAS长时间的不成功,则会给CPU带来非常大的开销。CAS 在并发量不是很高的情况下效率远远高于锁机制。还有一种策略就是限制CAS自旋的次数,在JUC中有些地方就使用了这种策略,例如阻塞队列中的SynchronousQueue。

②只能保证一个共享变量原子操作

CAS只能针对一个共享变量,如果是多个共享变量有三种方案:

  • 一是使用锁;
  • 二是把多个变量合并为一个变量,比如有两个共享变量 i=2,j=a,合并一下 ij=2a,然后用CAS来操作ij;
  • 三是把多个变量放在一个对象里来使用,AtomicReference类进行CAS操作改变引用地址以达到修改变量的目的。

③ABA问题
ABA问题
… …

CAS VS synchronized

对于资源竞争较少(线程冲突较轻)的情况,使用synchronized同步锁进行线程阻塞和唤醒切换以及用户态内核态间的切换操作额外浪费消耗cpu资源;而CAS基于硬件实现,不需要进入内核,不需要切换线程,操作自旋几率较少,因此可以获得更高的性能。

对于资源竞争严重(线程冲突严重)的情况,CAS自旋的概率会比较大,从而浪费更多的CPU资源,效率低于synchronized。

补充: synchronized 在 jdk1.6 之后,已经改进优化。synchronized 的底层实现主要依靠 Lock-Free 的队列,基本思路是自旋后阻塞,竞争切换后继续竞争锁,稍微牺牲了公平性,但获得了高吞吐量。在线程冲突较少的情况下,可以获得和 CAS 类似的性能;而线程冲突严重的情况下,性能远高于 CAS。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/855512.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号