15.unsafe类的CAS是怎么保证原子性的?

2023年 10月 3日 25.4k 0

老王:小陈啊,上一章我们讲了usafe是个啥东西,以及unsafe提供的几大类的功能

老王:这一章啊,我们要花个时间专门讲unsafe提供的cas功能,这个cas的功能是我们后面将Atomic原子类体系的基础。

小陈:cas功能?上一章的时候不是已经介绍过了吗?

老王:上一章只是简单的介绍了一下CAS功能而已,但是关于unsafe的cas功能底层是怎么保证原子性的?在操作系统层面是怎么实现的? 这些东西我们还没有讲。

由于的后面的并发知识非常多的使用到了unsafe的cas功能,所以啊,我们今天专门花一章的时间,来把CAS底层的原理弄懂

小陈:哦哦,原来是这样啊......

老王:上一章我们讲解CAS操作的时候,是直接通过( 对象地址 + 对象内部属性偏移量offset ) 直接定位到要修改的变量在内存的位置,然后在内存级别的比较数据和修改数据。也就是像下面的图一样:

操作的时候直接根据 o对象地址 + offset偏移量地址,定位到demo属性在内存的位置,然后直接操作内存修改数据。

image.png

老王:由于CPU是不会直接读写主存的,数据读取的时候还是先将数据读取到高速缓存,然后通过高速缓存传递给CPU;写数据的时候也是先高速缓存,然后再将高速缓存的数据写入内存;于是可以得到下面的图形:

image.png

老王:小陈啊,想想一下上面的那副图,如果在多线程并发操作的时候会有什么问题?

小陈:多个线程或者多个CPU同时读取和修改demo属性的时候,可能会导致数据不一致的问题,比如我拿一个 i++ 的例子来说:

比如CPU0、CPU1都通过内存地址定位到 i 所在位置,然后同时读取 i = 0,然后同时执行i++ 操作,再刷新会主内存,这个时候就会导致 i 的值不是我们想要的

image.png

老王:你说的没错,如果在多个CPU都可以同时操作一个共享变量的时候,就会出现你说的这个问题。

小陈:我记得CAS操作是可以保证原子性的,也就是同一个时间,同一个操作只允许一个CPU操作成功,它这个又是怎么保证的呢?

老王:这个啊,其实CAS底层的操作,还是会用到锁的!!! ,只不过这个锁是比较轻量级的,不会导致线程沉睡,下面我来讲讲CAS加锁来保证原子性的原理。

CAS底层使用锁保证原子性

老王:说起CAS操作啊,我还是画图给你比较好讲一点:

image.png

(1)首先CPU0要执行CAS操作对变量 i 进行赋值,然后CPU0****告诉总线说我要申请单独操作变量 i 的权限,帮我告诉一下CPU1等其它的CPU兄弟

(2)总线通知到了CPU1,CPU1告诉总线,好的,我不会操作数据,让CPU0大胆的去操作吧

(3)然后总线告诉CPU0,你可以独占变量 i 的操作了,其它的兄弟表示不会干扰你

(4)然后CPU0从自己的缓存读取 变量 i 的值;然后又根据  (o对象地址 + offset偏移量地址) 直接定位到变量 i 在内存的位置,直接读取变量 i 在内存的值

(5)接下来的操作就简单了,由于不会有人干扰,直接对比缓存的值和内存的值是否一致就可以了,如果一致,我直接修改,然后刷回主内存;如果不一致,说明我本地的数据不是最新的,需要重新申请CAS操作。

老王:小陈啊,这个就是CAS在底层操作的原理,它底层还是通过加锁来保证原子性的,同一个时间只能有一个CPU能申请到CAS的操作权限,你理解了吗?

小陈:哈哈,老王,你画的这个图太好了,我看到图就知道它是怎么操作的了,真牛啊......

老王:好的,那这一张CAS底层加锁保证原子性的讨论我们就到这里了,我们明天继续...

小陈:好的,老王......

老王:我们从下一章开始,就开始进入JUC提供的Atomic原子类的学习了......

小陈:那我们下一章见。

目录

JAVA并发专题 《筑基篇》

1.什么是CPU多级缓存模型?

2.什么是JAVA内存模型?

3.线程安全之可见性、有序性、原子性是什么?

4.什么是MESI缓存一致性协议?怎么解决并发的可见性问题?

JAVA并发专题《练气篇》

5.volatile怎么保证可见性?

6.什么是内存屏障?具有什么作用?

7.volatile怎么通过内存屏障保证可见性和有序性?

8.volatile为啥不能保证原子性?

9.synchronized是个啥东西?应该怎么使用?

10.synchronized底层之monitor、对象头、Mark Word?

11.synchronized底层是怎么通过monitor进行加锁的?

12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁

13.synchronized怎么保证可见性、有序性、原子性?

JAVA并发专题《结丹篇》

14. JDK底层Unsafe类是个啥东西?

15.unsafe类的CAS是怎么保证原子性的?

16.Atomic原子类体系讲解

17.AtomicInteger、AtomicBoolean的底层原理

18.AtomicReference、AtomicStampReference底层原理

19.Atomic中的LongAdder底层原理之分段锁机制

20.Atmoic系列Strimped64分段锁底层实现源码剖析

JAVA并发专题《金丹篇》

21.AQS是个啥?为啥说它是JAVA并发工具基础框架?

22.基于AQS的互斥锁底层源码深度剖析

23.基于AQS的共享锁底层源码深度剖析

24.ReentrantLock是怎么基于AQS实现独占锁的?

25.ReentrantLock的Condition机制底层源码剖析

26.CountDownLatch 门栓底层源码和实现机制深度剖析

27.CyclicBarrier 栅栏底层源码和实现机制深度剖析

28.Semaphore 信号量底层源码和实现机深度剖析

29.ReentrantReadWriteLock 读写锁怎么表示?

  • ReentrantReadWriteLock 读写锁底层源码和机制深度剖析
  • JAVA并发专题《元神篇》并发数据结构篇

    31.CopyOnAarrayList 底层分析,怎么通过写时复制副本,提升并发性能?

    32.ConcurrentLinkedQueue 底层分析,CAS 无锁化操作提升并发性能?

    33.ConcurrentHashMap详解,底层怎么通过分段锁提升并发性能?

    34.LinkedBlockedQueue 阻塞队列怎么通过ReentrantLock和Condition实现?

    35.ArrayBlockedQueued 阻塞队列实现思路竟然和LinkedBlockedQueue一样?

    36.DelayQueue 底层源码剖析,延时队列怎么实现?

    37.SynchronousQueue底层原理解析

    JAVA并发专题《飞升篇》线程池底层深度剖析

  • 什么是线程池?看看JDK提供了哪些默认的线程池?底层竟然都是基于ThreadPoolExecutor的?
  • 39.ThreadPoolExecutor 构造函数有哪些参数?这些参数分别表示什么意思?

    40.内部有哪些变量,怎么表示线程池状态和线程数,看看道格.李大神是怎么设计的?

  • ThreadPoolExecutor execute执行流程?怎么进行任务提交的?addWorker方法干了啥?什么是workder?

  • ThreadPoolExecutor execute执行流程?何时将任务提交到阻塞队列? 阻塞队列满会发生什么?

  • ThreadPoolExecutor 中的Worker是如何执行提交到线程池的任务的?多余Worker怎么在超出空闲时间后被干掉的?

  • ThreadPoolExecutor shutdown、shutdownNow内部核心流程

  • 再回头看看为啥不推荐Executors提供几种线程池?

  • ThreadPoolExecutor线程池篇总结

  • 相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论