Atomic是基于unsafe类自旋操作实现的,下面以AtomicInteger类为例进行讲解。

要理解Atomic得先了解CAS

CAS

CAS全程Compare And Swap ,是条并发原语,功能是判断内存中某个值是否与预期值相等,相等就用新值更新旧值,否则不更新。

Java中CAS是基于unsafe类实现的,所有的unsafe类中的方法都是native类修饰的,直接调用操作系统底层资源执行响应的任务。

unsafe.compareAndSwapInt(this, valueOffset, expect, update);

这是一条调用unsafe类中的compareAndSwapInt的方法,this表示当前对象,valueoffset表示当前对象的偏移地址,expect表示预期值

update表示更新值。作用是如果预期值和该对象偏移地址中的值一样,就用更新值更新偏移地址中的值。

AtomicInteger类初始化

// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset; static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
} private volatile int value;

上述代码是AtomicInteger类的默认参数初始化过程。其中value就是我们想要进行操作的那个值。加上volatile是为了

保证修改该值后立马被其他线程感知到。

刚开始实例化unsafe类,这没什么好说的,因为AtomicInteger类中方法都是通过unsafe类中方法来操作的。在静态代码块中通过

unsafe.objectFieldOffset方法获取value值的偏移量。也可以说是引用地址,以后通过该地址就可以随时获取value值和更改value值

AtomicInteger中方法的执行流程

这里我们以常用的getAndIncrement方法为例

/**
* Atomically increments by one the current value.
*
* @return the previous value
*/
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}

可以看到,该方法是调用unsafe类中的getAndAddInt方法,继续跟踪该方法,进入unsafe类源代码中

可以看到,调用unsafe类中getIntVolatile方法,方法参数var1为传入的对象,即上述的AtomicInteger类的对象

var2为偏移地址,该方法的作用是通过该对象的偏移地址找到值,也就是找到上文的value值。(注意!这里已经

不是在AtomicInteger类源代码中了而是进入了Unsafe类源代码中,所以这里的this.getIntVolatile是unsafe类中的

getIntVolatile方法,该方法不是在AtomicInteger类中!)获取到目前的value值后调用compareAndSwapInt方法,

使用获取到的value值和当前当前对象地址偏移量中的值进行比较,如果相同就更新值,并且退出循环,否则就继续

进入循环获取该偏移地址中的最新值。为什么这里会导致使用var5 = getIntVolatile获取偏移地址中的值后后面compareAndSwapInt

方法var5又会出现不等于偏移量地址上的值呢?按道理来说两次获取同一个偏移地址上的值是肯定会相同的,但是这里我们

考虑多线程的情况下,当两个线程同时获取当前偏移地址上的值,由于compareAndSwapInt是原子操作,所以必定有一个

线程会先执行完,并且改掉内存偏移地址上的值,那么另一个线程就会出现两次获取内存偏移地址上的值却不一致的情况,

出现这种情况就需要重新获取该值并且在此执行compareAndSwapInt,直到成功为止。

CAS与synchronized比较

CAS支持多个线程并发修改。并发程度高

synchronized一次只有一个线程修改,并发程度较低

CAS只支持一个共享变量的原子操作

synchronized可以对个变量进行加锁

CAS会出现ABA问题

最新文章

  1. ubuntu配置ftp服务器
  2. 浏览器全屏事件(Html5)
  3. Microsoft Softwares
  4. Beta冲刺---Day2
  5. Qt开发环境中使用报表控件FastReport遇到的一些问题(二)
  6. IE浏览器GET传参后台乱码
  7. [shell基础]——awk命令
  8. char型变量中能存贮一个中文汉字
  9. lucene4入门(1)
  10. UIScrollView 滑动试图
  11. QF——UI之几种常用的隐藏键盘的方法
  12. DatabaseMetaData的用法(转)
  13. Ruby学习之动态调用
  14. Maven-02: 依赖
  15. ubuntu部分端口命令的使用----开启端口/开启防火墙
  16. Asp.Net MVC三层架构之autofac使用教程
  17. Docker学习笔记之Docker的数据管理和存储
  18. pip windows下的引入
  19. taglib简介
  20. Android ListView理解之BaseAdapter

热门文章

  1. Altium Designer入门学习笔记4:PCB设计中各层的含义
  2. 用decimal模块增加python的浮点数精度
  3. freertos知识点笔记——队列、二值信号量、计数信号量
  4. 最长回文子串——manacher
  5. jenkins配置邮箱时出错
  6. JSP 页面 jstl 时间戳 long型转时间
  7. js 常用判断
  8. 一个通用的分页存储过程实现-SqlServer(附上sql源码,一键执行即刻搭建运行环境)
  9. Python学习笔记——jupyter notebook 入门和中文pdf输出方案
  10. Stringsobits(模拟)