根据数据类型,可以将JUC包中的原子操作类可以分为4类。

1. 基本类型: AtomicInteger, AtomicLong, AtomicBoolean ;
2. 数组类型: AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray ;
3. 引用类型: AtomicReference, AtomicStampedRerence, AtomicMarkableReference ;
4. 对象的属性修改类型: AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater 。

这些类存在的目的是对相应的数据进行原子操作。所谓原子操作,是指操作过程不会被中断,保证数据操作是以原子方式进行的 其底层都是使用CAS(Compare And Set)实现。

CAS: CAS的机制就相当于“非阻塞算法”,CAS是由CPU硬件实现,所以执行相当快.CAS有三个操作参数:内存地址,期望值,要修改的新值,当期望值和内存当中的值进行比较不相等的时候,表示内存中的值已经被别线程改动过,这时候失败返回,当相等的时候,将内存中的值改为新的值,这一系列的操作是原子的。

CAS是所有原子变量的原子性的基础,其原因就在于这个native操作会最终演化为一条CPU指令cmpxchg,而不是多条CPU指令。由于CAS仅仅是一条指令,因此它不会被多线程的调度所打断,所以能够保证CAS操作是一个原子操作。补充一点,当代的很多CPU种类都支持cmpxchg操作,但不是所有CPU都支持,对于不支持的CPU,会自动加锁来保证其操作不会被打断。

这是一种不加锁而实现操作原子化的一种巧妙的编程方式,不仅在Java的jvm种,甚至在操作系统的底层并发实现机制中也有CAS的大量应用。

但是这种方式有没有缺点呢?

CAS缺点

CAS虽然很高效的解决原子操作,但是CAS仍然存在三大问题。ABA问题,循环时间长开销大和只能保证一个共享变量的原子操作

1.  ABA问题。因为CAS需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就会变成1A-2B-3A。

从Java1.5开始JDK的atomic包里提供了一个类AtomicStampedReference来解决ABA问题。这个类的compareAndSet方法作用是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。

2. 循环时间长开销大。自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销(即使没有任何争用也会做一些无用功)。如果JVM能支持处理器提供的pause指令那么效率会有一定的提升,pause指令有两个作用,第一它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零。第二它可以避免在退出循环的时候因内存顺序冲突(memory order violation)而引起CPU流水线被清空(CPU pipeline flush),从而提高CPU的执行效率。

3. 只能保证一个共享变量的原子操作。当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁,或者有一个取巧的办法,就是把多个共享变量合并成一个共享变量来操作。比如有两个共享变量i=2,j=a,合并一下ij=2a,然后用CAS来操作ij。从Java1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行CAS操作(会增加程序测试的复杂度,稍不注意就会出现问题)。

参考:http://www.cnblogs.com/skywang12345/p/3514589.html

最新文章

  1. HDU-4689 Derangement DP
  2. Modem常用概念
  3. boost::thread 线程锁
  4. Android开发--推送
  5. [Cycle.js] From toy DOM Driver to real DOM Driver
  6. 验证abc三列数字符合我的小弟要求
  7. Spring 注入数据源
  8. NYOJ 330 一个简单的数学
  9. 机器学习 —— 类不平衡问题与SMOTE过采样算法
  10. BZOJ4083 : [Wf2014]Wire Crossing
  11. AlexNet实践
  12. QT---实现舒尔特方格(零基础入门)
  13. 4.5 C++重载、覆盖和遮蔽
  14. 2017-2018-2 20165318 实验三《Java面向对象程序设计》实验报告
  15. Android Studio 之 打包生成的 apk 安装包装到手机上闪退
  16. ios中Pldatabase的用法(4)
  17. JS的 instanceof 方法
  18. R302指识别开发笔记
  19. MySQL 事务没有提交导致 锁等待 Lock wait timeout exceeded
  20. jdk 配置

热门文章

  1. MFC中的CDC详细教程
  2. Web前端开发规范收集
  3. NSIS隐藏窗体标题栏自带的button(最大化,最小化,关闭X)
  4. vue 中 this.$router.push() 路由跳转传参 及 参数接收的方法
  5. Sqlserver 实际开发中表变量的用法
  6. Redis主从同步分析
  7. Java IDL与javaRMI
  8. 开发ActiveX控件调用另一个ActiveX系列2——调试ActiveX
  9. oracle函数中lead,lag,over,partition by 的使用
  10. OpenCV 中的三大数据类型:IplImage 类型