CAS是什么?

比较并交换

例子1:

public class ABADemo1 {
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(5);
System.out.println(atomicInteger.compareAndSet(5,2019)+"\t当前值是:"+atomicInteger.get());
System.out.println(atomicInteger.compareAndSet(5,1024)+"\t当前值是:"+atomicInteger.get());
}
} 结果如下:


CAS底层原理?

1.自旋锁

2.UnSafe类

atomicInteger.getAndIncrement();

底层调用的其实是unsafe方法,关系见下图:

va1 AtomicInteger对象本身。

var2 该对象的引用地址。

var4 需要变动的数量。

var5  是用var1 var2找出的主内存中真实的值,用该对象当前的值与var5比较,如果相同,更新var5+var4并且返回true,如果不同,继续取值然后再比较,直到更新完成。(自旋)

最后通过native调用本地方法,该方法的实现位于unsafe.cpp中。

 1.Unsafe类:

是CAS的核心类,由于Java方法无法直接访问底层系统,需要通过本地方法(native)来访问,Unsafe相当于一个后门,基于该类可以直接操作特定内存的数据。Unsafe类存在于sun.misc包中,其内部方法操作可以像C的指针一样直接操作内存,因为java 中CAS的操作执行依赖于Unsafe类的方法。

注意Unsafe类中的所有方法都是native修饰的,也就是说Unsafe类中的方法都直接调用操作系统底层资源执行相应任务

2.变量valueOffset,表示该变量值在内存中的偏移地址,因为Unsafe就是根据内存偏移地址来获取数据的。

public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}

3.变量vaue用volatile修饰,保证了多线程之间的内存可见性。

CAS 的全称为Compare-And-Swap,它是一条CPU并发原语。

它的功能是判断内存某个位置的值是否为预期值,这个过程是原子的

CAS并发原语体现在Java语言就是sun.misc.Unsafe类中的各个方法。调用UnSafe类中的CAS方法,JVM会帮我们实现CAS汇编指令。这是一种完全依赖于硬件的功能。通过它实现了原子操作。再次强调,由于CAS是一种系统原语,原语属于操作系统用于范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,再执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。


CAS 的缺点

1.循环时间长开销很大。

2.只能保证一个共享变量的原子操作。

3.会有ABA问题。

CAS会导致"ABA问题"

CAS算法实现一个重要前提需要取出内存中某时刻的数据并再当下时刻比较并替换,那么再这个时间差会导致数据的变化。

比如说一个线程one从内存位置V中取出A,这时候另一个线程two也从内存中取出A,并且线程two进行了一些操作将值变成了B,然后线程two又将V位置的数据变成A,  这时候线程one进行CAS操作发现内存中仍然是A,然后线程one操作成功。尽管线程one的CAS操作成功,但不代表这个操作过程就是没有问题的。


AtomicReference原子引用例子:

@Getter
@ToString
@AllArgsConstructor
class User {
String userName;
int age;
} /**
* AtomicReference原子引用,想对某个类进行包装,可以参考这个类的写法
*/
public class AtomicReferenceDemo { public static void main(String[] args) {
User z3 = new User("z3",22);
User li4 = new User("li4",25);
AtomicReference<User> atomicReference = new AtomicReference<>();
atomicReference.set(z3);
System.out.println(atomicReference.compareAndSet(z3,li4)+"\t"+atomicReference.get().toString());
System.out.println(atomicReference.compareAndSet(z3,li4)+"\t"+atomicReference.get().toString());
}
} 运行结果见下图:


解决ABA问题 加版本号例子:

public class ABADemo {
static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100,1);
public static void main(String[] args) {
System.out.println("-------------存在ABA问题");
new Thread(() ->{
atomicReference.compareAndSet(100,101);
atomicReference.compareAndSet(101,100);
},"T1").start(); new Thread(() ->{
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(atomicReference.compareAndSet(100,2019) +"\t" +atomicReference.get());
},"t2").start(); try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
} System.out.println("-------------以下是解决ABA问题"); new Thread(() ->{
int stamp = atomicStampedReference.getStamp();
System.out.println(Thread.currentThread().getName()+"\t第1次版本号"+stamp);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
atomicStampedReference.compareAndSet(100,101,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
System.out.println(Thread.currentThread().getName()+"\t第2次版本号"+atomicStampedReference.getStamp());
atomicStampedReference.compareAndSet(101,100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
System.out.println(Thread.currentThread().getName()+"\t第3次版本号"+atomicStampedReference.getStamp());
},"t3").start(); new Thread(() ->{
int stamp = atomicStampedReference.getStamp();
System.out.println(Thread.currentThread().getName()+"\t第1次版本号"+stamp);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
boolean result = atomicStampedReference.compareAndSet(100,2019,stamp,stamp+1);
System.out.println(Thread.currentThread().getName()+"\t修改成功否"+result+"\t 当前版本号"+atomicStampedReference.getStamp()); System.out.println(Thread.currentThread().getName()+"\t当前实际最新值"+atomicStampedReference.getReference());
},"t4").start();
}
}
运行结果见下图:

CAS是什么的更多相关文章

  1. .NET应用和AEAI CAS集成详解

    1 概述 数通畅联某综合SOA集成项目的统一身份认证工作,需要第三方系统配合进行单点登录的配置改造,在项目中有需要进行单点登录配置的.NET应用系统,本文专门记录.NET应用和AEAI CAS的集成过 ...

  2. SuperMap-iServer-单点登录功能验证(CAS)

    SuperMap-iServer-单点登录功能验证(CAS) 1.测试目的: 验证SuperMap-iServer使用CAS单点登录的功能是否正常. 2.测试环境: SuperMap-iServer8 ...

  3. 集成基于CAS协议的单点登陆

    相信大家对单点登陆(SSO,Single Sign On)这个名词并不感到陌生吧?简单地说,单点登陆允许多个应用使用同一个登陆服务.一旦一个用户登陆了一个支持单点登陆的应用,那么在进入其它使用同一单点 ...

  4. 【Java并发编程实战】-----“J.U.C”:CAS操作

    CAS,即Compare and Swap,中文翻译为"比较并交换". 对于JUC包中,CAS理论是实现整个java并发包的基石.从整体来看,concurrent包的实现示意图如下 ...

  5. 多线程同步工具——CAS原子变量

    这是我参考的一篇文章<基于CAS的乐观锁实现>,讲述的是一种需要CPU支持的执行技术CAS(Compare and Swap). 首先理解什么是原子性操作,意思是不能再拆分的操作,例如改写 ...

  6. CAS FOR WINDOW ACTIVE DIRECTORY SSO单点登录

    一.CAS是什么? CAS(Central Authentication Service)是 Yale 大学发起的一个企业级的.开源的项目,旨在为 Web 应用系统提供一种可靠的单点登录解决方法(支持 ...

  7. CAS Client集群环境的Session问题及解决方案

    [原创申明:文章为原创,欢迎非盈利性转载,但转载必须注明来源] 之前写过一篇文章,介绍单点登录的基本原理.这篇文章重点介绍开源单点登录系统CAS的登录和注销的实现方法.并结合实际工作中碰到的问题,探讨 ...

  8. cas单点登录搭建

    Cas Server下载:http://developer.jasig.org/cas/ Cas Client下载:http://developer.jasig.org/cas-clients/ 测试 ...

  9. CAS环境搭建

    实验背景: 系统环境: Windows XP  |  SUN JDK1.6U4 | Tomcat6.0.14 | CAS Server 3.1.1 + CAS Client 2.1.1 主机完整名称: ...

  10. ovirt配置为cas登录

    准备工作 Ovirt测试机.CAS服务器.AD服务器 cas.crt -- CAS服务器的CA证书 allwinner.cer -- CAS服务器的证书颁发机构根证书 Ovirt测试机要求:apach ...

随机推荐

  1. 【js】vue 2.5.1 源码学习 (十) $mount 挂载函数的实现

    大体思路(九) 本节内容: 1. $mount 挂载函数的实现. // 将Vue.prototype.$mount 缓存下来 ==>mountComponet(this,el) { // 组建挂 ...

  2. P1066 汪老师玩卡片

    题目描述 汪老师得到了一些卡片,这些卡片上标有数字0或5.现在他可以选择其中一些卡片排成一列,使得排出的一列数字组成的数最大,且满足被90整除这个条件.同时这个数不能含有前导0,即0不能作为这串数的首 ...

  3. P1054 全组合

    题目描述 给定n,m,按字典序输出所有从1-n里面取出m个数的组合.比如从1-3里面取出2个的组合是: 1 2 1 3 2 3 输入格式 输入两个数n,m.其中 \(0<n<=10,0&l ...

  4. Server,Servlet,ServletConfig,ServletContext,Session,Request,Response

    Server流程 解析URL->找到应用->找到Servlet->实例化Servlet->调用init->调用service->返回响应->调用destroy ...

  5. 2019-3-8-为何使用-DirectComposition

    title author date CreateTime categories 为何使用 DirectComposition lindexi 2019-3-8 8:56:9 +0800 2018-04 ...

  6. 2019-1-20-VisualStudio-安装-Python-开发

    title author date CreateTime categories VisualStudio 安装 Python 开发 lindexi 2019-01-20 10:51:15 +0800 ...

  7. spring MVC 核心配置

    <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.spr ...

  8. mysql主从之主机名导致主从机制失败的问题

    一 主库 mysql主服务器的正确配置需要指定log-bin.log-bin-index server-id = 1 log-bin=master-bin log-bin-index = master ...

  9. 【题解】毒蛇越狱(FWT+容斥)

    [题解]毒蛇越狱(FWT+容斥) 问了一下大家咋做也没听懂,按兵不动没去看题解,虽然已经晓得复杂度了....最后感觉也不难 用FWT_OR和FWT_AND做一半分别求出超集和和子集和,然后 枚举问号是 ...

  10. XRPC之接口双向调用

    一般远程接口调用的服务都是基于客户端主动调用服务端,由服务端来提供相关的接口服务:在新版本的XRPC中引入了一个新的功能,即接口双向通讯,组件提供服务创建客户会话的接口代理并调用客户提供的接口服务.接 ...