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. C# 编辑

    if (state == "编辑") { ht["修改人"] = Helper.用户名; ht["修改时间"] = DateTimeHelp ...

  2. 【java工具类】上传文件

    /**上传文件 * @param file 文件 * @param filePath 上传文件路径,不包含文件名 * @param fileName 新的文件名 * @return 返回一个路径名 * ...

  3. 关系型数据库(七),复杂SQL语句

    目录 1.SQL语句由六部分组成 2.Group By 和HAVING 七.复杂SQL语句 1.SQL语句由六部分组成 Select  *** From  *** Where  *** Group B ...

  4. CodeForces 788B--Weird journey

    Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Description Little ...

  5. 安装python及其它

    https://www.liaoxuefeng.com/wiki/1016959663602400/1016959856222624

  6. 第七周课程总结 & 实验报告(五)

    第七周课程总结 一.抽象类与接口的应用 1.实例化 2.实际应用 ---模板设计(抽象类) ---制定标准(接口) 3.设计模式 ---工厂设计 ---代理设计 ---适配器设计 二.抽象类与接口之间 ...

  7. 简易的文件上传 tp5

    /** * 保存新建的资源 * @return \think\Response */ public function save() { //判断一下提交类型 if ($this->request ...

  8. HearthBuddy炉石兄弟 Method 'CollectionDeckBoxVisual.IsValid' not found.

    [CollectionManagerScene_COLLECTION] An exception occurred when calling CacheCustomDecks: System.Miss ...

  9. 展示组件(Presentational component)和容器组件(Container component)之间有何不同

    展示组件关心组件看起来是什么.展示专门通过 props 接受数据和回调,并且几乎不会有自身的状态,但当展示组件拥有自身的状态时,通常也只关心 UI 状态而不是数据的状态.(子组件)容器组件则更关心组件 ...

  10. 集合(Java总结一)

    一.Queue 一个队列就是一个先入先出(FIFO)的数据结构 1.没有实现的阻塞接口的LinkedList: 实现了java.util.Queue接口和java.util.AbstractQueue ...