并发编程(五):CAS
在atomic包中,大多数类都是借助unsafe类来实现的,如以下代码
public static AtomicInteger count = new AtomicInteger(0);
private static void add() {
count.incrementAndGet();
}
incrementAndGet()方法的实现如下:
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
我们再继续深入getAndInt()方法,实现如下:
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
在以上代码中我们着重要说的是 compareAndSwapInt(var1, var2, var5, var5 + var4) 这个方法,compareAndSwap,取每个单词首写字母,就是我们经常说的cas。这个方法中有四个参数var1为当前对象,即代码中的count,var2为当前值,如想计算2加上1等于3的操作,var2即为2,var4为增加量,也就是这个例子中的1,var5为调用底层方法得到的底层当前的值,如果没有其他线程改变底层当前值,返回为2,compareAndSwapInt方法的作用为,如果var2(当前值)与var5(底层当前值相等)则将底层值覆盖为底层当前值(var5)+增加量(var4),否则(其他线程更改了底层当前值,var5不等于var2),重新从底层方法取一次var5的值,如此时var5=4,并重新从var1(当前对象)取一次var2的值,如此时var2的值也变为4,则采取相加操作覆盖底层值,如果var2与var5仍不等,则继续循环取值,直到相等为止。
总结一下,CAS操作包含三个操作数,内存位置(V),预期原值(A)和新值(B),如果内存位置的值与预期原值相匹配,处理器会自动将该位置值更新为新值,否则处理器不做任何操作。CAS指令一般都返回该位置的值(有特殊情况只返回是否成功),CAS简而言之就是,我认为位置V应该包含值A,如果包含该值,就将B放到这个位置,否则不更改该位置的值,只告诉我这个位置现在的值即可 。
对于getIntVolatile方法和compareAndSwapInt的实现如下:
public native int getIntVolatile(Object var1, long var2);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
可将两个方法都由native修饰,native修饰的方法为底层方法,一般由c语言来实现。
锁分为悲观锁和乐观锁,独占锁是一种悲观锁,synchronized是一种独占锁,如果锁被占用,其他需要锁的线程就会被挂起,直到持有锁的线程释放锁,它会产生的问题如下:
a、在多线程竞争下,加锁释放锁会导致比较多的上下文切换和调度延时,引起性能问题
b、如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能风险
另一种就是乐观锁,它每次执行时并不加锁而是假设没有冲突的去完成操作,如果因为冲突失败就重试,直到成功为止,而客观锁用到的机制就是CAS。虽然CAS可以很高效的解决原子操作,但是CAS仍然存在三大问题:
a、ABA问题,如果一个值原来是A,后被改成B,之后又改为A,那么使用CAS进行检查时发现它的值并没有发生变化,但是实际上却发生变化了,ABA问题的解决思路就是使用版本号,在变量面前加上版本号,每次变量更新的时候把版本加一,上面博客中我们提到atomic包中有专门的类来解决ABA问题
b、循环时间长开销大。CAS循环如果长时间不成功,会给CPU带来非常大的执行开销。如果JVM能支持处理器提供的pause指令则效率会有一定的提升,pause指令有两个作用,推迟流水线执行,使cpu不会消耗过多的执行资源和避免退出循环的时候因内存顺序冲突而引起CPU流水线被清空,提高CPU执行效率
c、只能保证一个共享变量的原子操作。当对一个共享变量执行操作时,我们可以使用循环CAS来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候可以用锁或把多个共享变量合并成一个共享变量来操作或者把多个变量放在一个对象里(atomic包中有对引用类型的原子操作)来进行CAS操作
并发编程(五):CAS的更多相关文章
- 【Java并发编程五】信号量
一.概述 技术信号量用来控制能够同时访问某特定资源的活动的数量,或者同时执行某一给定操作的数据.计数信号量可以用来实现资源池或者给一个容器限定边界. 信号量维护了一个许可集,许可的初始量通过构造函数传 ...
- java并发编程(八) CAS & Unsafe & atomic
参考文档:https://www.cnblogs.com/xrq730/p/4976007.html CAS(Compare and Swap) 一个CAS方法包含三个参数CAS(V,E,N).V表示 ...
- Java并发编程 (五) 线程安全性
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 一.安全发布对象-发布与逸出 1.发布与逸出定义 发布对象 : 使一个对象能够被当前范围之外的代码所使用 ...
- 聊聊CAS - 面试官最喜欢问的并发编程专题
什么是CAS 学习Java并发编程,CAS(Compare And Set)机制都是一个不得不掌握的知识点.除了通过synchronized进行并发控制外,还可以通过CAS的方式控制,大家熟悉的Ree ...
- Java并发(一)并发编程的挑战
目录 一.上下文切换 1. 多线程一定快吗 2. 测试上下文切换次数和时长 3. 如何减少上下文切换 4. 减少上下文切换实战 二.死锁 三.资源限制的挑战 四.本章小结 并发编程的目的是为了让程序运 ...
- java(9)并发编程
整理自<java 并发编程的艺术> 1. 上下文切换 即使是单核处理器也支持多线程执行代码,CPU通过给每个线程分配CPU时间片来实现这个机制.时间片是CPU分配给各个线程的时间,因为时间 ...
- 读《Java并发编程的艺术》(一)
离开博客园很久了,自从找到工作,到现在基本没有再写过博客了.在大学培养起来的写博客的习惯在慢慢的消失殆尽,感觉汗颜.所以现在要开始重新培养起这个习惯,定期写博客不仅是对自己学习知识的一种沉淀,更是在督 ...
- java并发编程的艺术——第一章总结
并发编程的挑战 1.1上下文切换 1.2死锁 1.3资源限制的挑战 1.4本章小结 1.1上下文切换 1.1.1多线程一定快吗 1.1.2测试上下文切换次数和时长 1.1.3如何减少上下文切换 1.1 ...
- 《Jave并发编程的艺术》学习笔记(1-2章)
Jave并发的艺术 并发编程的挑战 上下文切换 CPU通过时间片分配算法来循环执行任务,当前时间片执行完之后会切换到下一个任务.但是,切换会保存上一个任务的状态,一遍下次切换回这个任务时,可以再次加载 ...
- Java并发编程的挑战
并发编程的目的是为了让程序运行得更快,但是,并不是线程启动的越多,就能让程序最大限度地并发执行.并发编程时,会面临非常多的挑战,比如上下文切换的问题,死锁的问题,以及受限于各种硬件和软件的资源限制问题 ...
随机推荐
- Windows远程连接的实现
实验室有一台电脑,寝室里也有一台电脑,很多时候,事情还没有做完就不得不离开实验室,所以,在寝室里远程控制实验室的电脑是一件很有"意义"的事,其实,Windows系统已经 ...
- 自定义android 4.0以上的对话框风格
做个笔记,这里是Dialog的风格,如果是用AlertDialog创建的,不能直接用.在styles.xml的写法: <style name="DialogWindowTitle&qu ...
- 数据库隔离级别(mysql+Spring)与性能分析
数据库隔离级别与Spring配置事务的联系及性能影响,以下是个人理解,如果有瑕疵请及时指正. 这里以mysql为例,先明确以下几个问题: 一.一般项目如果不自己配置事务的话,一般默认的是au ...
- 流密码和RC4
定义:流密码是对称密码算法,从明文输入流逐位或逐字节产生密文输出. 实例:使用最广泛的流密码是RC4. 流密码结构: 流密码类似于”一次一密”,不同的是”一次一密”使用的是真正的随机数流,而流密码使用 ...
- 记一个SwipeMenuListView侧滑删除错乱的Bug
做侧滑删除网上有很多方案,比如重写Listview实现滑动的监听,今天说下一个SwipeListView,这个是之前一个朋友在网上开源的一个封装组件,能够适用于多种情况,项目地址:https://gi ...
- 利用openssl管理证书及SSL编程第3部分:将MinGW编译的openssl dll导出def和lib供MSVC使用
将MinGW编译的openssl dll导出def和lib供MSVC使用 前面我们用mingw把openssl 编译成了动态库,得到下面2个dll文件: libeay32.dll ssleay32.d ...
- pycharm+django之小试牛刀
准备好好学习一下python,就从django开始吧,顺带了解一下网站的开发.今天在windows上安装了python,django,以及酷炫吊的IDE--pycharm,学习资料主要是<the ...
- Chapter 2 User Authentication, Authorization, and Security(9):防止登录名和用户查看元数据
原文出处:http://blog.csdn.net/dba_huangzj/article/details/39003679,专题目录:http://blog.csdn.net/dba_huangzj ...
- QT Mobile: 一统IOS/Andriod/WP/等移动平台的江湖
笔者在研究生阶段做了2年的QT开发,那时候QT在嵌入式的图形开发中非常火,当时Nokia在智能机的份额还是第一.想当年,Nokia从Trolltech的手中收购了QT,当时大家还在例会上讨论QT终于不 ...
- python调用数据库并查询
http://blog.csdn.net/pipisorry/article/details/48024795 python调用数据库命令 conn = sqlite3.connect(". ...