CAS机制总结
一、简介
CAS机制:(Compare and set)比较和替换
简单来说–>使用一个期望值来和当前变量的值进行比较,如果当前的变量值与我们期望的值相等,就用一个新的值来更新当前变量的值
CAS有三个操作数:内存值V、旧的预期值A、要修改的值B,当且仅当预期值A和内存值V相同时(条件),将内存值修改为B并返回true,否则条件不符合返回false。条件不符合说明该变量已经被其它线程更新了。
二、用途
CAS的使用场景:juc下ReentryLock 和 Atomic类操作
CAS乐观锁(循环内自旋):原理:A=内存值,thread1对A进行累加操作后的值为B。更新内存值时会判断A和B是否相等,如果相等,那么B替换A退出循环,如果不相等,重新获得内存值,进行操作。此套流程如何保证内存值是最新的?详见volatile原理此套流程如何保证V,A比较B替换V时是原子操作?cas底层用unsafe直接访问底层操作系统,做了硬件级别的原子操作。
AtomicInteger源码分析 :
java.util.concurrent.atomic包下的原子操作类都是基于CAS实现的,接下去我们通过AtomicInteger来看看是如何通过CAS实现原子操作的:
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
// setup to use Unsafe.compareAndSwapInt for updates
//获得unsafe实例
private static final Unsafe unsafe = Unsafe.getUnsafe();
//存放变量value的内存偏移
private static final long valueOffset;
static {
try {
//通过unsafe获得value的内存偏移
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
//volatile修饰的,保证了多线程之间看到的value值是同一份,后面会分析
private volatile int value;
接下来看看设置新的值是如何完成的:
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
这里很简单,直接调用unsafe的cas方法就可以了,通过value的内存偏移,以及期望的值来设置新的值。接下来就是本地方法调用了。
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
同样原子增加的操作就是通过unsafe来完成,只是每次都是增加1而已。
可以去看看其他几个原子操作类:AtomicLong(原子更新长整型)AtomicBoolean(原子更新布尔类型,用int来实现的),AtomicIntegerArray(原子更新整型数组里的元素),AtomicReference(原子更新引用类型)等,其核心思想都是用unsafe提供的原子操作来完成的。
在Java并发编程的艺术中,作者实现了一个基于CAS线程安全的计数器和一个非线程安全的计数器,本质就是用原子操作类代替一般的int或者Long数据类型,通过原子操作类来完成原子操作,保证了计数的线程安全,但是这里提一下,原子操作类不是什么时候都是线程安全的,当由原子操作类来完成复合操作是,此时就不一定是线程安全的了。
AtomicInteger a=new AtomicInteger(10);
//假设下面会出现线程竞争
int b=a.get();
if (b==10){
a.compareAndSet(10,100);
}
在多线程中,这样就不是线程安全的了,因为先取出某个值,然后在判断,这整个操作不是原子操作。
三、优缺点
cas优点:
如一描述在并发量不是很高时cas机制会提高效率。
cas缺点:
1.循环时间开销太大:
如果CAS长时间执行不成功,则会给CPU带来交大的执行开销。处理器提供一种pause指令可以缓解这部分问题,pause指令有两个作用,第一它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零。第二它可以避免在退出循环的时候因内存顺序冲突(memory order violation)而引起CPU流水线被清空(CPU pipeline flush),从而提高CPU的执行效率。
2。只能保证一个共享变量的原子操作。
如果需要对多个共享变量进行同步,就得使用锁,或者将几个共享变量封装起来,使用CAS来进行同步。从Java1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行CAS操作
3、ABA问题
aba问题:内存值V=100;
threadA 将100,改为50;
threadB 将100,改为50;
threadC 将50,改为100;
场景:小牛取款,由于机器不太好使,多点了几次全款操作。后台threadA和threadB工作,
此时threadA操作成功(100->50),threadB阻塞。正好牛妈打款50元给小牛(50->100),
threadC执行成功,之后threadB运行了,又改为(100->50)。
牛气冲天,lz钱哪去了???
如何解决aba问题:对内存中的值加个版本号,在比较的时候除了比较值还的比较版本号。
java:AtomicStampedReference就是用版本号实现cas机制。
CAS机制总结的更多相关文章
- 深入浅出Java并发包—CAS机制
在JDK1.5之前.Java主要靠synchronized这个关键字保证同步,已解决多线程下的线程不安全问题,但是这会导致锁的发生,会引发一些个性能问题. 锁主要存在一下问题 (1)在多线程竞争下,加 ...
- CAS机制与自旋锁
CAS(Compare-and-Swap),即比较并替换,java并发包中许多Atomic的类的底层原理都是CAS. 它的功能是判断内存中某个地址的值是否为预期值,如果是就改变成新值,整个过程具有原子 ...
- 什么是CAS机制?(转)
围绕下面四个点展开叙述: 一:什么是CAS机制? 二:Java当中CAS的底层实现 三:CAS的ABA问题和解决方法 四:java8对CAS的优化 一:什么是CAS机制? 我们先看一段代码: 启动两个 ...
- Java CAS同步机制 原理详解(为什么并发环境下的COUNT自增操作不安全): Atomic原子类底层用的不是传统意义的锁机制,而是无锁化的CAS机制,通过CAS机制保证多线程修改一个数值的安全性。
精彩理解: https://www.jianshu.com/p/21be831e851e ; https://blog.csdn.net/heyutao007/article/details/19 ...
- 线程安全之CAS机制详解(分析详细,通俗易懂)
背景介绍:假设现在有一个线程共享的变量c=0,让两个线程分别对c进行c++操作100次,那么我们最后得到的结果是200吗? 1.在线程不安全的方式下:结果可能小于200,比如当前线程A取得c的值为3, ...
- (白话理解)CAS机制
(白话理解)CAS机制 通过一段对话我们来了解cas用意 示例程序:启动两个线程,每个线程中让静态变量count循环累加100次. 最终输出的count结果是什么呢?一定会是200吗? 加了同步锁之后 ...
- 并发之atomicInteger与CAS机制
并发之atomic与CAS自旋锁 通过前几章的讲解我们知道i++这种类似操作是不安全的.针对这种情况,我们可能会想到利用synchronize关键字实现线程同步,保证++操作的原子性,的确这是一种有效 ...
- 对CAS机制的理解(一)
先看一段代码:启动两个线程,每个线程中让静态变量count循环累加100次. public class CountTest { public static int count = 0; public ...
- 对CAS机制的理解(二)
一.Java当中CAS的底层实现首先看看AtomicInteger的源码,AtomicInteger中常用的自增方法 incrementAndGet: public final int increme ...
- 详解java中CAS机制所导致的问题以及解决——内存顺序冲突
[CAS机制] 指的是CompareAndSwap或CompareAndSet,是一个原子操作,实现此机制的原子类记录着当前值的在内存中存储的偏移地址,将内存中的真实值V与旧的预期值A做比较,如果不一 ...
随机推荐
- 《Visual C++ 2010入门教程》系列二:安装、配置和首次使用VS2010
作者:董波 日期:2010.6.15 写在前面 在我还在上学的时候,我选择了C++,最初我用VC6作为我的IDE,我看过很多本C++的教材,有的适合我,有的不适合我,其中有一本叫<Visual ...
- bzoj 3872 [ Poi 2014 ] Ant colony —— 二分
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3872 从食蚁兽所在的边向叶节点推,会得到一个渐渐放大的取值区间,在叶子节点上二分有几群蚂蚁符 ...
- 前端之html第一天
一.内容
- 在datagrid中,IE浏览器报错:SCRIPT5007: 无法获取属性“rowspan”的值: 对象为 null 或未定义
项目总采用datagird时,产生界面如下图原本标题上有功能按钮,此时消失 错误:SCRIPT5007: 无法获取属性"rowspan"的值: 对象为 null 或未定义, 造 ...
- myeclipse 导入maven
一安装maven 先安装jdk,配置JAVA_HOME 把下载的maven bin包,解压到指定目录,比如:D:\apache-maven-3.3.9-bin 配置maven的系统变量M2_HOME和 ...
- 值得网页设计师&前端收藏的实用工具列表
原文地址:http://www.uisdc.com/tool-list-web-developers# 无论你是经验丰富的前端,还是刚刚起步的设计师,这些为真正的网页设计师和开发者所准备的实用工具.在 ...
- Vijos P1951 玄武密码 (AC自动机)
描述 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中.老人们说,这是玄武神灵将天书藏匿在此. 很多年后,人们终于在 ...
- UVa 1471 Defense Lines (二分+set优化)
题意:给定一个序列,然后让你删除一段连续的序列,使得剩下的序列中连续递增子序列最长. 析:如果暴力枚举那么时间复杂度肯定受不了,我们可以先进行预处理,f[i] 表示以 i 结尾的连续最长序列,g[i] ...
- 洛谷 P2764 最小路径覆盖问题【匈牙利算法】
经典二分图匹配问题.把每个点拆成两个,对于原图中的每一条边(i,j)连接(i,j+n),最小路径覆盖就是点数n-二分图最大匹配.方案直接顺着匹配dsf.. #include<iostream&g ...
- P4323 [JSOI2016]独特的树叶(树哈希)
传送门 树哈希?->这里 反正大概就是乱搞--的吧-- //minamoto #include<bits/stdc++.h> #define R register #define l ...