• JUC03-volatile、CAS及并发原子类


    一、 Volatile

    Volatile可以用来修饰成员变量和静态成员变量,保证可见性、有序性

    可见性:保证volatile修饰的变量每次读取都会从主从中进行读取而不是cpu缓存
    有序性:对Volatile修饰变量进行写操作时,会在该操作后加上写屏障,进行读操作时会在读操作前加上读屏障。

    读写屏障

    写屏障(sfence)保证在该屏障之前的,对共享变量的改动,都同步到主存当中,并且会确保指令重排序时,禁止屏障前后的写操作跨越屏障。

    读屏障(lfence)保证在该屏障之后,对共享变量的读取,加载的是主存中最新数据。并且会确保指令重排序时,禁止屏障前后的读操作跨越屏障

    重排序

    在这里插入图片描述

    二、CAS

    cas是compareAndSet的缩写,底层使用cpu指令,是一个比较并赋值的原子操作

    结合 CAS 和 volatile 可以实现无锁并发,适用于线程数少、多核 CPU 的场景下。

    • CAS 是基于乐观锁的思想:最乐观的估计,不怕别的线程来修改共享变量,就算改了也没关系,我吃亏点再重试呗。
    • synchronized 是基于悲观锁的思想:最悲观的估计,得防着其它线程来修改共享变量,我上了锁你们都别想改,我改完了解开锁,你们才有机会。

    CAS 体现的是无锁并发、无阻塞并发,请仔细体会这两句话的意思
    因为没有使用 synchronized,所以线程不会陷入阻塞,这是效率提升的因素之一
    但如果竞争激烈,可以想到重试必然频繁发生,反而效率会受影响

    相比于

    三、 原子累加器LongAdder

    与之前提到的AtomicInteger不同,LongAdder 累加器采取了效率更高的方法应对高并发情况对数据的累加需求

    优化一:多个cell分摊并发压力

    LongAdder 关键字段

    // 累加单元数组, 懒惰初始化
    transient volatile Cell[] cells;
    // 基础值, 如果没有竞争, 则用 cas 累加这个域
    transient volatile long base;
    // 在 cells 创建或扩容时, 置为 1, 表示加锁
    transient volatile int cellsBusy;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    当执行add(x)操作时大概执行流程如下:

    1. 判断当前是否发生过竞争

      • 若没有则使用cas对base进行累加
    2. 若有则判断当前线程是否有对应cell

      • 有则使用cas对该cell进行累加
    3. 若没有或者对base的cas累加失败或者对cell的cas累加失败

    4. 创建新的cell进行累加(具体创建与否需要根据机器cpu的核心数量)

    5. 将所有cell的值进行求和返回

    优化二:缓存行伪共享

    不同CPU的寄存器中用到了不同的变量,一个用到的是X,一个用到的是Y,并且XY在同一个缓存行中,这就叫做缓存行伪共享

    所谓缓存行就是cpu缓存的单位,每个缓存行大小为64个字节。当对缓存行中一个数据进行修改时,整个缓存行都将失效
    在这里插入图片描述
    LongAdder内部维护一个cells数组,包含多个cell(累加单元),每个cell绑定一或多个线程来分摊并发压力,然而,即使不同的cell对应不同的线程,但伪共享的出现会导致线程1对一个cell的修改导致另一个cell的值失效,需要重新从内存读取,大大影响其性能
    在这里插入图片描述

    @Contended注解填充缓存行解决伪共享

    此注解可以填充被修饰的对象,使一个缓存行最多只能存储一个该对象,解决伪共享问题
    在这里插入图片描述

    总结

    LongAdder通过使用多个cell分摊并发压力提高累加器性能,并且用@Contended注解修饰Cell对象,使其能够独占缓存行,解决了缓存行伪共享的问题。而AutomicInteger内部只用一个变量用来表示当前值,在高并发下多个线程争抢该变量性能损耗较大。

  • 相关阅读:
    GitLab项目组相关操作(创建项目组Group、创建项目组的项目、为项目添加成员并赋予权限)
    【LeetCode】戳气球 [H](记忆化搜索)
    二肽二氨基丁酰苄基酰胺二乙酸盐/Dipeptide Diaminobutyroyl Benzylamide Diacetate/SYN-AKE
    联邦学习概述与现状
    手撕 视觉slam14讲 ch7 / pose_estimation_3d2d.cpp (2)
    计算点云每个点与Z轴的垂直度(附open3d python代码)
    用VS软件开发“浪漫烟花“<笔记摘录>
    JavaScript 64 JavaScript 函数 64.1 JavaScript 函数定义
    基于AT89S52的俄罗斯方块游戏设计与实现
    spring security oauth2
  • 原文地址:https://blog.csdn.net/qq_42861526/article/details/127825092