【JUC系列第三篇】-CAS算法详解
作者 : 毕来生
微信: 878799579
1、CAS是什么?
CAS是英文单词(Compare-And-Swap)的缩写,中文意思是:比较并替换。CAS需要有3个操作数:内存地址V,旧的预期值A,即将要更新的目标值B。
CAS指令执行时,当且仅当内存地址V的值与预期值A相等时,将内存地址V的值修改为B,否则就什么都不做。整个比较并替换的操作是一个原子操作。
Cas乐观锁算法演示
CAS优缺点
优点:
- 解决了部分情况下原子操作的问题
- 并发量不是很高时cas机制会提高效率。
缺点:
同一时间只能保证一个共享变量的原子操作(针对多个共享变量操作。循环CAS无法保证操作原子性,需要考虑通过加锁来保证原子性)
循环时间比较长,且开销时间比较大 : 如果尝试CAS失败,则会一直进行尝试。如果一直不成功。会对CPU带来较大负担
经典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算法详解的更多相关文章
- OSGi 系列(三)之 bundle 详解
OSGi 系列(三)之 bundle 详解 1. 什么是 bundle bundle 是以 jar 包形式存在的一个模块化物理单元,里面包含了代码,资源文件和元数据(metadata),并且 jar ...
- 安全体系(三)——SHA1算法详解
本文主要讲述使用SHA1算法计算信息摘要的过程. 安全体系(零)—— 加解密算法.消息摘要.消息认证技术.数字签名与公钥证书 安全体系(一)—— DES算法详解 安全体系(二)——RSA算法详解 为保 ...
- Spring之旅第三篇-Spring配置详解
上一篇学习了IOC的概念并初步分析了实现原理,这篇主要学习Spring的配置,话不多说,让我们开始! 一.Bean元素配置 1.1 基本配置 看一个最基本的bean配置 <bean name=& ...
- G1混合式GC与三色标记算法详解【纯理论】
继续基于上一次https://www.cnblogs.com/webor2006/p/11146273.html的理论进一步了解G1. G1收集概览: G1算法将堆划分为若干个区域(Region),它 ...
- Kafka 系列(三)—— Kafka 生产者详解
一.生产者发送消息的过程 首先介绍一下 Kafka 生产者发送消息的过程: Kafka 会将发送消息包装为 ProducerRecord 对象, ProducerRecord 对象包含了目标主题和要发 ...
- SpringBoot第三篇:配置文件详解二
作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/10615605.html 版权声明:本文为博主原创文章,转载请附上博文链接! 前言 本文主要讲 ...
- Elasticsearch第三篇:查询详解
从第一篇开始,我用的ES版本就是7.8.0的,与低版本略有不同,不同点可以参考官方介绍,最大的不同就是抛弃 type 这一概念,为了方便测试,首先建立一个学生成绩的索引库(在建立的同时,规定字段类型, ...
- 安全体系(一)—— DES算法详解
本文主要介绍了DES算法的步骤,包括IP置换.密钥置换.E扩展置换.S盒代替.P盒置换和末置换. 安全体系(零)—— 加解密算法.消息摘要.消息认证技术.数字签名与公钥证书 安全体系(二)——RSA算 ...
- Java并发编程之CAS第三篇-CAS的缺点及解决办法
Java并发编程之CAS第三篇-CAS的缺点 通过前两篇的文章介绍,我们知道了CAS是什么以及查看源码了解CAS原理.那么在多线程并发环境中,的缺点是什么呢?这篇文章我们就来讨论讨论 本篇是<凯 ...
随机推荐
- PowerShell->>获取本地计算机的用户组和组成员
获取本地计算机的用户组和组成员 function Get-LocalGroups() { net localgroup | ?{ $_ -match "^\*.*" } | %{ ...
- 用css美化select框
先上代码: .selectData{ height: 0.42rem; position: absolute; right:.28rem; top:.30rem; //去边框 border: none ...
- 正则与re模块
一.正则表达式 在线测试工具 http://tool.chinaz.com/regex/ 1.字符组 在同一个位置可能出现的各种字符组成一个字符组,在正则表达中用[ ]表示 一个正则就是一条匹 ...
- 【Python基础】01_Python中的变量
1.定义和运算: 变量名 = 值 定义变量举例: # 定义一个变量 myCar = "比亚迪F0" # 输出一个变量 print(myCar) 变量之间的简单运算举例: price ...
- python-pillow图像处理模块
from PIL import ImageColor ImageColor.getcolor('red','RGB') #颜色 模式 ImageColor.getcolor('red','RGBA') ...
- WUST Oracle数据库 实验一实验二
链接:https://pan.baidu.com/s/1hCzvTLzXhyItP2gD_69gzg 提取码:j68f 复制这段内容后打开百度网盘手机App,操作更方便哦
- (十一)Hibernate中的多表操作(1):单向一对多
一.单向一对多() 案例一(用XML文件配置): 一个班级有多个学生,班级可以查看所有学生的信息. ClassBean.java package bean; import java.util.Hash ...
- Nginx实现同一端口HTTP跳转HTTPS
小目标:在只监听一个端口的情况下,将http访问跳转为https. 一般情况下http协议使用80端口,https协议443端口.要实现http强制转https是非常简单的事,随便都可以找到很多方案. ...
- python爬视频实例
例:抓取PhotoShop视频教程 网址http://www.mxiaobei.com/?id=424 import requests import re from bs4 import Beauti ...
- powerdesign中逆向工程后name和comment的互换
powerdesign 中,将数据库中可以逆向生成pdm的结构图,比较清晰看到系统的结构, 但假如是db先行的话,一般是db中的每个列中用comment中文注释说明这列是 干什么的,但逆向工程后,会发 ...