CAS,即Compare and Swap,中文翻译为“比较并交换”。

对于JUC包中,CAS理论是实现整个java并发包的基石。从整体来看,concurrent包的实现示意图如下:

i++是一个非常经典的操作,它几乎充斥着我们每个人编写的代码中。我们知道i++是可以分解的,它分解为getI()、i + 1 、setI三个步骤,所以它并不是原子操作。如果i==1,执行两次i++操作,我们期望的结果是3,但是结果有可能也是2:

那么有什么办法解决这个问题呢?肯定有!使用锁即可:

synchronized(this){
i++;
}

诚然,在java中存在乐观锁、悲观锁两种锁。其中synchronized就是悲观锁,在前面我们了解synchronized也是独占锁,加入关键字synchronized的代码一般都是以单线程的形式在运行着,它会导致其他需要该资源的线程挂起直到前面的线程执行完毕释放资源,所以它的效率较为低下。而乐观锁则采用了一种较为高效的方式,它的操作与synchronized不同,synchronized采用加锁,而它则不采用加锁去执行某些操作,如果发生了冲突则失败并一直重试直到成功为止。而CAS就是一种乐观锁,它所采用的策略是当且仅当预期值A和存中的值V相同,则将内存V值修改为B,否则返回V。实现如下:

for(;;){
if(A==V){
V = B;
}
}

当然在J.U.C中实现CAS没有这么简单。

CAS

CAS,即一种对内存中的共享数据进行操作的指令,而且该操作是原子的读写操作。其过程如下:首先CPU将内存中的将要被修改的数据与预期的值进行比较,如果这两个值相等,CPU则会将内存中数值替换为新值,否则不做操作。最后,CPU会将旧值返回。在java中,CAS的含义就是“我认为的原本的值是什么,如果你是,则更换为新值,否则不做修改同时麻烦告诉我该值时多少”

在CAS中,总共存在三个操作数:预期值A、内存中的V、修改的值B。当且仅当预期值A和内存中的值V相同,则将内存V值修改为B,否则返回V。使用这种机制编写的算法也叫作非阻塞算法,标准定义了一个线程的失败或者挂起是不会影响其他线程的失败或者挂起。

下面我们来已AtomicIneger的源码为例来看看CAS操作:

public final int getAndAdd(int delta) {
for (;;) {
int current = get();
int next = current + delta;
if (compareAndSet(current, next))
return current;
}
}

这里很显然使用CAS操作(for(;;)里面),他每次都从内存中读取数据,+1操作,然后两个值进行CAS操作。如果成功则返回,否则失败重试,直到修改成功为止。

上面源码最关键的地方有两个,一个for循环,它代表着一种宁死不屈的精神,不成功誓不罢休。还有就是compareAndSet:

public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

CAS的缺陷

尽管CAS机制可以使我们不依赖与同步,不影响和挂起其他线程,它大大提升了运行的效率,但是它会导致一个ABA的问题,如下:加入有两个线程A、B,他们都读取内存中的数据V,假如这个时候线程A,先将V修改为V1,然后又修改为V,这个时候线程B的compareAndSet仍然能成功,对于线程B而言该值V并没有发生任何变化,而实际上它已经变化了,只不过最后又还原了而已。

 

参考文献

1、Java的多线程编程模型5--Java中的CAS理论

2、JAVA CAS原理深度分析

【Java并发编程实战】-----“J.U.C”:CAS操作的更多相关文章

  1. 【Java并发编程实战】-----“J.U.C”:ReentrantReadWriteLock

    ReentrantLock实现了标准的互斥操作,也就是说在某一时刻只有有一个线程持有锁.ReentrantLock采用这种独占的保守锁直接,在一定程度上减低了吞吐量.在这种情况下任何的"读/ ...

  2. 【Java并发编程实战】-----“J.U.C”:CountDownlatch

    上篇博文([Java并发编程实战]-----"J.U.C":CyclicBarrier)LZ介绍了CyclicBarrier.CyclicBarrier所描述的是"允许一 ...

  3. 【Java并发编程实战】-----“J.U.C”:CyclicBarrier

    在上篇博客([Java并发编程实战]-----"J.U.C":Semaphore)中,LZ介绍了Semaphore,下面LZ介绍CyclicBarrier.在JDK API中是这么 ...

  4. 【Java并发编程实战】-----“J.U.C”:Semaphore

    信号量Semaphore是一个控制访问多个共享资源的计数器,它本质上是一个"共享锁". Java并发提供了两种加锁模式:共享锁和独占锁.前面LZ介绍的ReentrantLock就是 ...

  5. 【Java并发编程实战】-----“J.U.C”:ReentrantLock之三unlock方法分析

    前篇博客LZ已经分析了ReentrantLock的lock()实现过程,我们了解到lock实现机制有公平锁和非公平锁,两者的主要区别在于公平锁要按照CLH队列等待获取锁,而非公平锁无视CLH队列直接获 ...

  6. 【Java并发编程实战】-----“J.U.C”:ReentrantLock之一简介

    注:由于要介绍ReentrantLock的东西太多了,免得各位客官看累,所以分三篇博客来阐述.本篇博客介绍ReentrantLock基本内容,后两篇博客从源码级别分别阐述ReentrantLock的l ...

  7. 【Java并发编程实战】----- AQS(四):CLH同步队列

    在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形.其主要从两方面进行了改造:节点的结构与节点等待机制.在结构上引入了头 ...

  8. 【Java并发编程实战】—– AQS(四):CLH同步队列

    在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形. 其主要从双方面进行了改造:节点的结构与节点等待机制.在结构上引入了 ...

  9. 【Java并发编程实战】----- AQS(二):获取锁、释放锁

    上篇博客稍微介绍了一下AQS,下面我们来关注下AQS的所获取和锁释放. AQS锁获取 AQS包含如下几个方法: acquire(int arg):以独占模式获取对象,忽略中断. acquireInte ...

  10. 《java并发编程实战》笔记

    <java并发编程实战>这本书配合并发编程网中的并发系列文章一起看,效果会好很多. 并发系列的文章链接为:  Java并发性和多线程介绍目录 建议: <java并发编程实战>第 ...

随机推荐

  1. [C#] C# 基础回顾 - 匿名方法

    C# 基础回顾 - 匿名方法 目录 简介 匿名方法的参数使用范围 委托示例 简介 在 C# 2.0 之前的版本中,我们创建委托的唯一形式 -- 命名方法. 而 C# 2.0 -- 引进了匿名方法,在 ...

  2. 谈谈如何使用Netty开发实现高性能的RPC服务器

    RPC(Remote Procedure Call Protocol)远程过程调用协议,它是一种通过网络,从远程计算机程序上请求服务,而不必了解底层网络技术的协议.说的再直白一点,就是客户端在不必知道 ...

  3. JavaScript 自定义对象

    在Js中,除了Array.Date.Number等内置对象外,开发者可以通过Js代码创建自己的对象. 目录 1. 对象特性:描述对象的特性 2. 创建对象方式:对象直接量.new 构造函数.Objec ...

  4. .NET Core的日志[5]:利用TraceSource写日志

    从微软推出第一个版本的.NET Framework的时候,就在“System.Diagnostics”命名空间中提供了Debug和Trace两个类帮助我们完成针对调试和跟踪信息的日志记录.在.NET ...

  5. Shell碎碎念

    1. 字符串如何大小写转换 str="This is a Bash Shell script." 1> tr方式 newstr=`tr '[A-Z]' '[a-z]' < ...

  6. java 利用ManagementFactory获取jvm,os的一些信息--转

    原文地址:http://blog.csdn.net/dream_broken/article/details/49759043 想了解下某个Java项目的运行时jvm的情况,可以使用一些监控工具,比如 ...

  7. [Egret]优雅的写http

    首先,自从使用链式调用的写法后,就一发不可收拾的喜爱上了这种优雅的方式.不管是写架构还是写模块,我都会不自觉的使用这种最优雅的方式.链式写法既减少了代码量,又非常优雅的. 在使用 egret 的htt ...

  8. pdo的使用

    PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口. PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据. PDO随 ...

  9. android 两种实现计时器时分秒的实现,把时间放在你的手中~

    可能我们在开发中会时常用到计时器这玩意儿,比如在录像的时候,我们可能需要在右上角显示一个计时器.这个东西其实实现起来非常简单. 只需要用一个控件Chronometer,是的,就这么简单,我都不好意思讲 ...

  10. FastClick 填坑及源码解析

    最近产品妹子提出了一个体验issue —— 用 iOS 在手Q阅读书友交流区发表书评时,光标点击总是不好定位到正确的位置: 如上图,具体表现是较快点击时,光标总会跳到 textarea 内容的尾部.只 ...