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. win10 uwp win2d CanvasVirtualControl 与 CanvasAnimatedControl

    本文来告诉大家 CanvasVirtualControl ,在什么时候使用这个控件. 在之前的入门教程win10 uwp win2d 入门 看这一篇就够了我直接用的是CanvasControl,实际上 ...

  2. dotnet 获取指定进程的输入命令行

    本文告诉大家如何在 dotnet 获取指定的进程的命令行参数 很多的程序在启动的时候都需要传入参数,那么如何拿到这些程序传入的参数? 我找到两个方法,一个需要引用 C++ 库支持 x86 和 x64 ...

  3. JavaScript模块化演变 CommonJs,AMD, CMD, UMD(一)

    原文链接:https://www.jianshu.com/p/33d53cce8237 原文系列2链接:https://www.jianshu.com/p/ad427d8879cb 前端完全手册: h ...

  4. [译文] 为什么你在 C# 里总是应该使用 "var" 关键字

    [译文] Why You Should Always Use the 'var' Keyword in C# (为什么你总是应该在 C# 里使用 "var" 关键字) Using ...

  5. 洛谷p1119--灾难后重建(Floyd不仅仅是板子)

    问题描述 询问次数  5 000 00,   顶点数  200 怎么办? dijkstra?对不起,超时了/. 时间限制是1秒,询问5 000 00 ,每次dijsktra要跑n*n*logm 次,稳 ...

  6. 天猫SSM项目学习记录(一)----第一个相对完整的SSM项目

    来源:  http://how2j.cn/k/tmall_ssm/tmall_ssm-1516/1516.html?p=78908 目的:记录一个相对完整的SSM项目模板 1.工具:idea2018商 ...

  7. Python 进程、线程、协程的介绍与使用

    一.必备的理论基础 二.操作系统发展史 三.进程理论 四.线程理论 五.协程 一.必备的理论基础 操作系统理论: 操作系统是一个协调\管理\控制计算机硬件资源与应用软件资源的控制程序 操作系统的两大功 ...

  8. 洛谷$P4322\ [JSOI2016]$最佳团体 二分+$dp$

    正解:二分+$dp$ 解题报告: 传送门$QwQ$ 这题长得好套路嗷,,,就一看就看出来是个$01$分数规划+树形$dp$嘛$QwQ$. 考虑现在二分的值为$mid$,若$mid\leq as$,则有 ...

  9. 洛谷$P2053\ [SCOI2007]$修车 网络流

    正解:网络流 解题报告: 传送门$QwQ$ 一个很妙的建图,,,说实话我麻油想到$QwQ$ 考虑对每个工人建$n$个点,表示这是他修的倒数第$i$辆车,就可以算出影响是$t\cdot i$,然后对每辆 ...

  10. WeihanLi.Npoi 1.7.0 更新

    WeihanLi.Npoi 1.7.0 更新介绍 Intro 昨天晚上发布了 WeihanLi.Npoi 1.7.0 版本,增加了 ColumnInputFormatter/ColumnOutputF ...