作者 : 毕来生

微信: 878799579


1、CAS是什么?

CAS是英文单词(Compare-And-Swap)的缩写,中文意思是:比较并替换。CAS需要有3个操作数:内存地址V,旧的预期值A,即将要更新的目标值B。

CAS指令执行时,当且仅当内存地址V的值与预期值A相等时,将内存地址V的值修改为B,否则就什么都不做。整个比较并替换的操作是一个原子操作。

Cas乐观锁算法演示

CAS优缺点

优点:

  1. 解决了部分情况下原子操作的问题
  2. 并发量不是很高时cas机制会提高效率。

缺点:

  1. 同一时间只能保证一个共享变量的原子操作(针对多个共享变量操作。循环CAS无法保证操作原子性,需要考虑通过加锁来保证原子性)

  2. 循环时间比较长,且开销时间比较大 : 如果尝试CAS失败,则会一直进行尝试。如果一直不成功。会对CPU带来较大负担

  3. 经典ABA问题

    如果内存地址V初次读取的值是A,并且在准备赋值的时候检查到它的值仍然为A,那我们就能说它的值没有被其他线程改变过了吗?

    如果在这段期间它的值曾经被改成了B,后来又被改回为A,那CAS操作就会误认为它从来没有被改变过。这个漏洞称为CAS操作的“ABA”问题。Java并发包为了解决这个问题,提供了一个带有标记的原子引用类“AtomicStampedReference”,它可以通过控制变量值的版本来保证CAS的正确性。因此,在使用CAS前要考虑清楚“ABA”问题是否会影响程序并发的正确性,如果需要解决ABA问题,改用传统的互斥同步可能会比原子类更高效。

如何解决经典ABA问题以及源码分析

通过JDK中自带的AtomicStampedReference类可以解决ABA问题。附上核心解决方法

	/**
* Atomically sets the value of both the reference and stamp
* to the given update values if the
* current reference is {@code ==} to the expected reference
* and the current stamp is equal to the expected stamp.
*
* @param expectedReference the expected value of the reference(期望值)
* @param newReference the new value for the reference(写入新值)
* @param expectedStamp the expected value of the stamp(期望的状态值)
* @param newStamp the new value for the stamp(新的状态值)
* @return {@code true} if successful
*/
public boolean compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
Pair<V> current = pair;
return
expectedReference == current.reference &&
expectedStamp == current.stamp &&
((newReference == current.reference &&
newStamp == current.stamp) ||
casPair(current, Pair.of(newReference, newStamp)));
} private boolean casPair(Pair<V> cmp, Pair<V> val) {
return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
}

因为casPair核心方法时通过native关键字修饰。故不能直接查看对应class源码。

public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5)

不能查看源码就能难住我们了?不存在的。

我们下载好openjdk源码后,将其导入到idea里该project的lib中,全局搜索。直接附上对应源码供大家参考

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h))
UnsafeWrapper("Unsafe_CompareAndSwapObject");
oop x = JNIHandles::resolve(x_h); // 新值
oop e = JNIHandles::resolve(e_h); // 预期值
oop p = JNIHandles::resolve(obj);
HeapWord* addr = (HeapWord *)index_oop_from_field_offset_long(p, offset);// 在内存中的具体位置
oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e, true);// 调用了另一个方法
jboolean success = (res == e); // 如果返回的res等于e,则判定满足compare条件(说明res应该为内存中的当前值),但实际上会有ABA的问题
if (success) // success为true时,说明此时已经交换成功(调用的是最底层的cmpxchg指令)
update_barrier_set((void*)addr, x); // 每次Reference类型数据写操作时,都会产生一个Write Barrier暂时中断操作,配合垃圾收集器
return success;
UNSAFE_END

【JUC系列第三篇】-CAS算法详解的更多相关文章

  1. OSGi 系列(三)之 bundle 详解

    OSGi 系列(三)之 bundle 详解 1. 什么是 bundle bundle 是以 jar 包形式存在的一个模块化物理单元,里面包含了代码,资源文件和元数据(metadata),并且 jar ...

  2. 安全体系(三)——SHA1算法详解

    本文主要讲述使用SHA1算法计算信息摘要的过程. 安全体系(零)—— 加解密算法.消息摘要.消息认证技术.数字签名与公钥证书 安全体系(一)—— DES算法详解 安全体系(二)——RSA算法详解 为保 ...

  3. Spring之旅第三篇-Spring配置详解

    上一篇学习了IOC的概念并初步分析了实现原理,这篇主要学习Spring的配置,话不多说,让我们开始! 一.Bean元素配置 1.1 基本配置 看一个最基本的bean配置 <bean name=& ...

  4. G1混合式GC与三色标记算法详解【纯理论】

    继续基于上一次https://www.cnblogs.com/webor2006/p/11146273.html的理论进一步了解G1. G1收集概览: G1算法将堆划分为若干个区域(Region),它 ...

  5. Kafka 系列(三)—— Kafka 生产者详解

    一.生产者发送消息的过程 首先介绍一下 Kafka 生产者发送消息的过程: Kafka 会将发送消息包装为 ProducerRecord 对象, ProducerRecord 对象包含了目标主题和要发 ...

  6. SpringBoot第三篇:配置文件详解二

    作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/10615605.html 版权声明:本文为博主原创文章,转载请附上博文链接! 前言   本文主要讲 ...

  7. Elasticsearch第三篇:查询详解

    从第一篇开始,我用的ES版本就是7.8.0的,与低版本略有不同,不同点可以参考官方介绍,最大的不同就是抛弃 type 这一概念,为了方便测试,首先建立一个学生成绩的索引库(在建立的同时,规定字段类型, ...

  8. 安全体系(一)—— DES算法详解

    本文主要介绍了DES算法的步骤,包括IP置换.密钥置换.E扩展置换.S盒代替.P盒置换和末置换. 安全体系(零)—— 加解密算法.消息摘要.消息认证技术.数字签名与公钥证书 安全体系(二)——RSA算 ...

  9. Java并发编程之CAS第三篇-CAS的缺点及解决办法

    Java并发编程之CAS第三篇-CAS的缺点 通过前两篇的文章介绍,我们知道了CAS是什么以及查看源码了解CAS原理.那么在多线程并发环境中,的缺点是什么呢?这篇文章我们就来讨论讨论 本篇是<凯 ...

随机推荐

  1. Linux软件安装管理---源码安装

    在Linux平台下,软件包的类型可以划分为两类:源码包.二进制包. 源码包: 即程序软件的源代码(一般也叫Tarball,即将软件的源码以tar打包后再压缩的资源包). 二进制包: 如 Red Hat ...

  2. MVC-初识

    RAZOR视图介绍 一个cshtml,主体是一个html文本,里面可以写前台和后台代码,混合编写(个人认为不太好,应该分离),这个文件最后会被会被编译为一个类(所以他可以像类一样写一些方法,其他的地方 ...

  3. CSP-S初赛

    初赛都过了好几天了,现在才想起来写点关于初赛的博客也真是...... 我是福建人,是在福建的赛点参加的CSP-S组的初赛,能力其实很弱,估分只能60多一点点.真是害怕一不小心这篇博客就变成了我的退役博 ...

  4. scratch少儿编程第一季——06、人在江湖混,没有背景怎么行。

    各位小伙伴大家好: 到上期我们学习了动作模块的全部指令.接下我们用动作模块做一个小小项目,来总结我们前面学的内容. 在做项目之前我们先来换一个背景. 在左下角舞台区,点击打开背景库,选择自己所需要的背 ...

  5. SAS学习笔记46 宏变量的可使用范围

    全局宏变量 在宏程序内部,除了使用%GLOBAL语句创建.在某些情况下,还可以直接使用DATA步中的CALL SYMPUT创建. 在一个宏程序中,在包含CALL SYMPUT的DATA步程序之前,如果 ...

  6. 如何知道外围器件的器件地址PHY_ADDR

    由于 S5P6818 现有的uboot没有网卡的初始化代码实现,在尝试移植网卡驱动而跟踪有关的源码的时候,不止一次地看到了类似下面的需要修改器件地址的有关写法. 根据原理图的有关硬件连接,找到对应的元 ...

  7. java 字符串处理的

    @Test public void testString(){ /*字符串处理 */ String email="123456789@qq.com"; System.out.pri ...

  8. rman备份跳过read only数据文件,减少备份总量,加快备份时间

    客户需求,RMAN备份时间过长,想缩短备份时间,优化备份. 客户基于表空间进行历史数据归档的方式,将历史的表空间进行read only,想让RMAN跳过只读表空间,减少RMAN备份的数据总量,从而缩短 ...

  9. hdu 6205 card card card 尺取法

    card card card Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  10. Rider开发开发.NET Framework 4.5项目遇到的一些问题

    使用rdier自带resharper功能,蛮爽的但是编译旧的项目时一直报错:Invalid option 'portable' for /debug; must be full or pdbonly' ...