1.CAS:
比较并交换(Compare And Swap),是Unsafe类中的一条CPU系统原语,原语的执行必须是连续的,在执行过程中不允许被中断,即CAS是一条CPU的原子指令,不会造成数据不一致问题。
类似:Atomic中的compareAndSet()方法
如果期望值和真实值相同,本次操作成功,如果不同则失败,这个过程是原子的
AtomicInteger atomicInteger = new AtomicInteger(5);
...
atomicInteger.compareAndSet(5, 2019); // 期望是5的时候,将其赋值为2019

2.Unsafe类:

rt.jar中的原生类,也是CAS的核心类,Unsafe类都是native修饰的,Unsafe类的方法都直接操作内存
以getAndIncrement()为例
atomicInteger.getAndIncrement();    // i++

AtomicInteger源码:

1)getAndIncrement()源码:

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

valueOffset为变量值在内存中的偏移地址

2)AtomicInteger的value和valueOffset成员

// 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;

unsafe类源码:

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;
}

var1为当前AtomicInteger对象,var2是该对象值的引用地址,var4是需要增加的数量

其过程为:
1)首先在物理内存中获取当前对象var1在var2地址上的值var5;
2)比较该地址当前最新的值和我获取到的值var5是否相等,如果相等,则赋值var5+var4;
3)否则重新获取重复1、2。
3.场景举例
假设线程A和线程B同时执行getAndAddInt操作(分别跑在不同CPU上)
1)AtomicInteger中value原始值为3,即主内存中为3,根据JMM模型,线程A和线程B各自持有一份value为3的副本分别在各自的工作内存中。
2)线程A通过getIntVolatile(var1, var2)拿到value的值3,这时线程A被挂起。
3)线程B也通过getIntVolatile(var1, var2)方法获取到value值3,刚好B没有被挂起并执行compareAdeSwapInt方法,比较内存值也为3,成功修改内存值为4,线程B执行完毕。
4)这时线程A恢复,执行compareAndSwapInt方法比较,发现自己工作内存中的value3和主内存中的4不一致,说明该值已经被其他线程抢先一步修改过了,线程A本次修改失败,只能重新读取重新来一遍了。
5)线程A重新获取value值,因为变量value被volatile修饰,所以其他线程对它的修改,线程A总是能够看到,线程A继续执行compareAndSwapInt进行比较替换,直到成功。
4.缺点:

1)CAS的方式相比于锁来说并发性加强了,但如果CAS失败,会一直进行尝试,可能会给CPU带来很大的开销
2)只能保证一个共享变量的原子性,对多个共享变量操作可以用锁来保证原子性。
3)引出ABA问题:不同线程执行时间不均衡导致慢的线程获取到虽然值与期望相等,却中间经历了别的线程更新操作。

Atomic实现原子性源码分析:CAS(比较并交换)、Unsafe类的更多相关文章

  1. Spring Developer Tools 源码分析:二、类路径监控

    在 Spring Developer Tools 源码分析一中介绍了 devtools 提供的文件监控实现,在第二部分中,我们将会使用第一部分提供的目录监控功能,实现对开发环境中 classpath ...

  2. Jetty 9 源码分析 Connector及Server类(一)

    本文的源码基于Jetty9,主要分析了Jetty 的Connector与Server类间在Jetty启动过程中的一些细节.Jetty9 对以前的Connector体系进行了重构, 结构与6和7都不同, ...

  3. [编织消息框架][netty源码分析]6 ChannelPipeline 实现类DefaultChannelPipeline职责与实现

    ChannelPipeline 负责channel数据进出处理,如数据编解码等.采用拦截思想设计,经过A handler处理后接着交给next handler ChannelPipeline 并不是直 ...

  4. tp5底层源码分析之------tp5.1类的自动加载机制

    tp框架作为国内主流框架,目前已经发布了6.0版本,相当于3.*版本是进行了重构,今天我们从源码的角度来研究下tp5.1自动加载的实现 作为单入口框架,从入口文件看起,入口文件在public/下,那么 ...

  5. [编织消息框架][netty源码分析]11 ByteBuf 实现类UnpooledHeapByteBuf职责与实现

    每种ByteBuf都有相应的分配器ByteBufAllocator,类似工厂模式.我们先学习UnpooledHeapByteBuf与其对应的分配器UnpooledByteBufAllocator 如何 ...

  6. phpcms 源码分析四: 数据库类实现

    这次是逆雪寒的数据库类分析: <?php /* 这个讲 phpcms 的数据库类 和 phpcms 的文本缓存的实现.看了看 都是很简单的东西.大家看着我注释慢慢看吧.慢慢理解,最好能装了PHP ...

  7. [netty源码分析]3 eventLoop 实现类SingleThreadEventLoop职责与实现

    eventLoop是基于事件系统机制,主要技术由线程池同队列组成,是由生产/消费者模型设计,那么先搞清楚谁是生产者,消费者内容 SingleThreadEventLoop 实现 public abst ...

  8. [编织消息框架][netty源码分析]4 eventLoop 实现类NioEventLoop职责与实现

    NioEventLoop 是jdk nio多路处理实现同修复jdk nio的bug 1.NioEventLoop继承SingleThreadEventLoop 重用单线程处理 2.NioEventLo ...

  9. [编织消息框架][netty源码分析]5 eventLoop 实现类NioEventLoopGroup职责与实现

    分析NioEventLoopGroup最主有两个疑问 1.next work如何分配NioEventLoop 2.boss group 与child group 是如何协作运行的 从EventLoop ...

随机推荐

  1. js 引号 转义字符 json字符串

    element_obj.NewTitle.value = json_obj.NewTitle.replace(/\"/g, "\""); model.NewTi ...

  2. nginx命令和配置

    centos 6.8安装的nginx 1.12.2 1.nginx常用的命令 使用nginx命令前,进入到/usr/local/nginx/sbin/目录 1)查看nginx版本 进入到/usr/lo ...

  3. Scratch的入门笔记

    最近发现人工智能和编程在小学开始普及,由于好奇,所以开始去了解儿童编程方面的知识,希望增加一些儿童编程教育相关的知识面,跟上发展潮流. Scratch是一款由麻省理工学院的“终身幼儿园团队”(Life ...

  4. 详解one-hot编码

    博主原创文章,转载请注明出处 https://www.cnblogs.com/shuaishuaidefeizhu/p/11269257.html 一.什么是one-hot编码? One-Hot编码, ...

  5. websocket协议解决消息发送问题 Could not decode a text frame as UTF-8.

    在使用websocket 时出现了Could not decode a text frame as UTF-8 首次连接成功当发送消息时,出现了编码作错误 第一请求页面时,连接成功 当发送消息时,不加 ...

  6. phpstorm 设置ftp自动保存服务器 (原)

    打开PHPstorm,依次  tools -  deployment  --  configuration 配置ftp或者sftp地址用户名密码等 端口号 要不就是 21 要不就是 22 , 22不行 ...

  7. 前端学习之三——jquery选择器

    Jquery中的选择器分为几大类:基本过滤选择器,层次选择器,内容过滤选择器,可见性过滤选择器,属性过滤选择器,子元素过滤选择器,表单对象选择器和表单对象属相过滤选择器. 1.非基本过滤选择器,一般需 ...

  8. html外部文件读取/写入

    1.文件的读取 外部文件读取控件: <input type="file" id="file_jquery" onchange="file_jqu ...

  9. tensorflow实现迁移学习

    此例程出自<TensorFlow实战Google深度学习框架>6.5.2小节 卷积神经网络迁移学习. 数据集来自http://download.tensorflow.org/example ...

  10. Python学习笔记:list的各种操作

    向一个列表中添加单个元素: my_list = []my_list.append('我爱你') 移除列表中的某个元素: my_list.pop(0) # 0是需要移除元素在列表中的index 或者是移 ...