在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的更多相关文章

  1. 【Java并发编程五】信号量

    一.概述 技术信号量用来控制能够同时访问某特定资源的活动的数量,或者同时执行某一给定操作的数据.计数信号量可以用来实现资源池或者给一个容器限定边界. 信号量维护了一个许可集,许可的初始量通过构造函数传 ...

  2. java并发编程(八) CAS & Unsafe & atomic

    参考文档:https://www.cnblogs.com/xrq730/p/4976007.html CAS(Compare and Swap) 一个CAS方法包含三个参数CAS(V,E,N).V表示 ...

  3. Java并发编程 (五) 线程安全性

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.安全发布对象-发布与逸出 1.发布与逸出定义 发布对象 : 使一个对象能够被当前范围之外的代码所使用 ...

  4. 聊聊CAS - 面试官最喜欢问的并发编程专题

    什么是CAS 学习Java并发编程,CAS(Compare And Set)机制都是一个不得不掌握的知识点.除了通过synchronized进行并发控制外,还可以通过CAS的方式控制,大家熟悉的Ree ...

  5. Java并发(一)并发编程的挑战

    目录 一.上下文切换 1. 多线程一定快吗 2. 测试上下文切换次数和时长 3. 如何减少上下文切换 4. 减少上下文切换实战 二.死锁 三.资源限制的挑战 四.本章小结 并发编程的目的是为了让程序运 ...

  6. java(9)并发编程

    整理自<java 并发编程的艺术> 1. 上下文切换 即使是单核处理器也支持多线程执行代码,CPU通过给每个线程分配CPU时间片来实现这个机制.时间片是CPU分配给各个线程的时间,因为时间 ...

  7. 读《Java并发编程的艺术》(一)

    离开博客园很久了,自从找到工作,到现在基本没有再写过博客了.在大学培养起来的写博客的习惯在慢慢的消失殆尽,感觉汗颜.所以现在要开始重新培养起这个习惯,定期写博客不仅是对自己学习知识的一种沉淀,更是在督 ...

  8. java并发编程的艺术——第一章总结

    并发编程的挑战 1.1上下文切换 1.2死锁 1.3资源限制的挑战 1.4本章小结 1.1上下文切换 1.1.1多线程一定快吗 1.1.2测试上下文切换次数和时长 1.1.3如何减少上下文切换 1.1 ...

  9. 《Jave并发编程的艺术》学习笔记(1-2章)

    Jave并发的艺术 并发编程的挑战 上下文切换 CPU通过时间片分配算法来循环执行任务,当前时间片执行完之后会切换到下一个任务.但是,切换会保存上一个任务的状态,一遍下次切换回这个任务时,可以再次加载 ...

  10. Java并发编程的挑战

    并发编程的目的是为了让程序运行得更快,但是,并不是线程启动的越多,就能让程序最大限度地并发执行.并发编程时,会面临非常多的挑战,比如上下文切换的问题,死锁的问题,以及受限于各种硬件和软件的资源限制问题 ...

随机推荐

  1. Java-IO之PrintStream(打印输出流)

    PrintStream是打印输出流,继承于FilterOutputStream,PrintStream是用来装饰其他输出流,为其他输出流添加功能,方便他们打印出各种数据值表示形式.与其他输出流不同,P ...

  2. 如何彻底的删除MySQL数据库(图文教程)

    最近有个小课题数据库使用Mysql,提前写一下Mysql作为复习. 第一步当然是要看如何卸载Mysql,因为安装之前要清理掉一切与Mysql有关的数据,否则后边安装失败. 以下操作以Window7操作 ...

  3. 【项目管理】 PMBOK 基础概念 (引论 PMBOK 笔记)

    好紧张, 3月28考试, 全力学 PMP ~~ 一. 项目 1. 项目的定义 项目 : 项目是为创造 独特 的 产品, 服务 或 成果 而进行的 临时性 工作; -- 独特 : 独特性是项目的特征, ...

  4. A*寻路算法入门(四)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...

  5. web安全认证机制知多少

    如今web服务随处可见,成千上万的web程序被部署到公网上供用户访问,有些系统只针对指定用户开放,属于安全级别较高的web应用,他们需要有一种认证机制以保护系统资源的安全,本文将探讨五种常用的认证机制 ...

  6. [C#]ToString("##")格式化用法案例一:自动编码单据流水码

    之前的写的自动编码单据流水码是写在存储过程或者函数中的,今天用程序写一个发现TOSTRING可以格式化方便. /// <summary> /// 年月日+两位流水码 /// </su ...

  7. Get Form type using javascript in CRM 2011

    Get from type var type = Xrm.Page.ui.getFormType(); getFromType() function returns integer value for ...

  8. 【Unity Shaders】概述及Diffuse Shading介绍

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  9. Android Studio 从安装到配置使用

    Android Studio是谷歌为android量身定制的IDE,在2013年谷歌大会上提出之后一直持续更新,现在已经是功能十分强劲的android开发工具,作为一个android开发者,还是早点转 ...

  10. Linux 中环境变量设置

    本文主要整理自以下博文: .bash_profile和.bashrc的什么区别及启动过程 linux环境变量设置方法总结(PATH/LD_LIBRARY_PATH) .bash_profile 和 . ...