【Java并发编程实战】-----“J.U.C”:CAS操作
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并没有发生任何变化,而实际上它已经变化了,只不过最后又还原了而已。
参考文献
【Java并发编程实战】-----“J.U.C”:CAS操作的更多相关文章
- 【Java并发编程实战】-----“J.U.C”:ReentrantReadWriteLock
ReentrantLock实现了标准的互斥操作,也就是说在某一时刻只有有一个线程持有锁.ReentrantLock采用这种独占的保守锁直接,在一定程度上减低了吞吐量.在这种情况下任何的"读/ ...
- 【Java并发编程实战】-----“J.U.C”:CountDownlatch
上篇博文([Java并发编程实战]-----"J.U.C":CyclicBarrier)LZ介绍了CyclicBarrier.CyclicBarrier所描述的是"允许一 ...
- 【Java并发编程实战】-----“J.U.C”:CyclicBarrier
在上篇博客([Java并发编程实战]-----"J.U.C":Semaphore)中,LZ介绍了Semaphore,下面LZ介绍CyclicBarrier.在JDK API中是这么 ...
- 【Java并发编程实战】-----“J.U.C”:Semaphore
信号量Semaphore是一个控制访问多个共享资源的计数器,它本质上是一个"共享锁". Java并发提供了两种加锁模式:共享锁和独占锁.前面LZ介绍的ReentrantLock就是 ...
- 【Java并发编程实战】-----“J.U.C”:ReentrantLock之三unlock方法分析
前篇博客LZ已经分析了ReentrantLock的lock()实现过程,我们了解到lock实现机制有公平锁和非公平锁,两者的主要区别在于公平锁要按照CLH队列等待获取锁,而非公平锁无视CLH队列直接获 ...
- 【Java并发编程实战】-----“J.U.C”:ReentrantLock之一简介
注:由于要介绍ReentrantLock的东西太多了,免得各位客官看累,所以分三篇博客来阐述.本篇博客介绍ReentrantLock基本内容,后两篇博客从源码级别分别阐述ReentrantLock的l ...
- 【Java并发编程实战】----- AQS(四):CLH同步队列
在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形.其主要从两方面进行了改造:节点的结构与节点等待机制.在结构上引入了头 ...
- 【Java并发编程实战】—– AQS(四):CLH同步队列
在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形. 其主要从双方面进行了改造:节点的结构与节点等待机制.在结构上引入了 ...
- 【Java并发编程实战】----- AQS(二):获取锁、释放锁
上篇博客稍微介绍了一下AQS,下面我们来关注下AQS的所获取和锁释放. AQS锁获取 AQS包含如下几个方法: acquire(int arg):以独占模式获取对象,忽略中断. acquireInte ...
- 《java并发编程实战》笔记
<java并发编程实战>这本书配合并发编程网中的并发系列文章一起看,效果会好很多. 并发系列的文章链接为: Java并发性和多线程介绍目录 建议: <java并发编程实战>第 ...
随机推荐
- XSS
XSS的含义 XSS(Cross Site Scripting)即跨站脚本.跨站的主要内容是在脚本上. 跨站脚本 跨站脚本的跨,体现了浏览器的特性,可以跨域.所以也就给远程代码或者第三方域上的代码提供 ...
- C语言 · 4-3水仙花数
问题描述 打印所有100至999之间的水仙花数.所谓水仙花数是指满足其各位数字立方和为该数字本身的整数,例如 153=1^3+5^3+3^3. 样例输入 一个满足题目要求的输入范例.例:无 样例输出 ...
- Asp.net MVC 传递数据 从前台到后台,包括单个对象,多个对象,集合
今天为大家分享下 Asp.net MVC 将数据从前台传递到后台的几种方式. 环境:VS2013,MVC5.0框架 1.基本数据类型 我们常见有传递 int, string, bool, double ...
- [APUE]UNIX进程的环境(上)
一. 前言 本章将学习:当执行程序时,其main函数是如何被调用的,命令行参数是如何传送给执行程序的,典型的存储器布局是什么样式,如何分配另外的存储空间,进程如何使用环境变量,进程终止的不同方式等.另 ...
- 23种设计模式--工厂模式-Factory Pattern
一.工厂模式的介绍 工厂模式让我们相到的就是工厂,那么生活中的工厂是生产产品的,在代码中的工厂是生产实例的,在直白一点就是生产实例的类,代码中我们常用new关键字,那么这个new出来的实例 ...
- Go结构体实现类似成员函数机制
Go语言结构体成员能否是函数,从而实现类似类的成员函数的机制呢?答案是肯定的. package main import "fmt" type stru struct { testf ...
- Git初探--笔记整理和Git命令详解
几个重要的概念 首先先明确几个概念: WorkPlace : 工作区 Index: 暂存区 Repository: 本地仓库/版本库 Remote: 远程仓库 当在Remote(如Github)上面c ...
- 解构C#游戏框架uFrame兼谈游戏架构设计
1.概览 uFrame是提供给Unity3D开发者使用的一个框架插件,它本身模仿了MVVM这种架构模式(事实上并不包含Model部分,且多出了Controller部分).因为用于Unity3D,所以它 ...
- 在centos7上安装Jenkins
在centos7上安装Jenkins 安装 添加yum repos,然后安装 sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins ...
- C#——传值参数(2)
//我的C#是跟着猛哥(刘铁猛)(算是我的正式老师)<C#语言入门详解>学习的,微信上猛哥也给我讲解了一些不懂得地方,对于我来说简直是一笔巨额财富,难得良师! 这次与大家共同学习C#中的 ...