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做比较,如果不一 ...
随机推荐
- AngularJS 指令(Directives)实践指南
指令(Directives)是所有AngularJS应用最重要的部分.尽管AngularJS已经提供了非常丰富的指令,但还是经常需要创建应用特定的指令.这篇教程会为你讲述如何自定义指令,以及介绍如何在 ...
- Linux共享内存(二)
Linux共享内存编程实例 原文链接:http://blog.csdn.net/pcliuguangtao/article/details/6526119 /*共享内存允许两个或多个进程进程共享同一块 ...
- ChartCtrl源码剖析之——CChartGrid类
CChartGrid类用来绘制波形区域中的表格,当绘制波形时波形就显示在这些表格上面.它处于该控件的区域,如下图所示: CChartGrid类的头文件. #if !defined(AFX_CHARTG ...
- combox组合框设置高度
组合框设置高度 转载 2013年10月24日 22:54:03 1033 MFC进行界面编程时,组合框CComboBox控件在可视化设计组件的时候是无法进行高度编辑的,但是我们在实际的项目中经常需要定 ...
- 【413】C 语言 Command line
Command-Line Arguments All the executable programs above have a main(void) program more generally, e ...
- Jedis线上的一个小坑:Redis有并发访问的数据错乱的问题
问题现象: 业务数据有错乱,A的一些数据有好几个都是B的数据 这些业务数据在保存在Redis缓存中,怀疑是并发情况下Jedis错乱的问题 原因分析: JedisUtil里面在使用完Jedis 后释放资 ...
- linux下的日志压缩脚本
linux下的日志压缩脚本: #!/bin/bash #第一步:先定义项目列表如下: projects="project-a project-b project-c project-d&qu ...
- python爬取网页图片(二)
从一个网页爬取图片已经解决,现在想要把这个用户发的图片全部爬取. 首先:先找到这个用户的发帖页面: http://www.acfun.cn/u/1094623.aspx#page=1 然后从这个页面中 ...
- Hello!六月
把这里当做记事本应该没人介意吧: 太忙了!六月! ACM: 背包九讲
- 题解报告:hdu 1203 I NEED A OFFER!(01背包)
Problem Description Speakless很早就想出国,现在他已经考完了所有需要的考试,准备了所有要准备的材料,于是,便需要去申请学校了.要申请国外的任何大学,你都要交纳一定的申请费用 ...