• 并发包中的原子类


    目录

    1.JUC包下的原子类

    2.Unsafe类

    3.Unsafe类的简单使用的问题

    4.那么我们怎么使用这个Unsafe类呢?

    JDK8以后的优化


     

    1.JUC包下的原子类

        使用原子类比使用锁的的效率高,因为这些原子类都是使用非阻塞的CAS算法实现的。具体是使用Unsafe类提供的方法实现的。

       

     

     总结起来就是一句话,如果在当前的var1类中,内存偏移地址为var2的变量,当前值等于var6,就给他加var4。

     原子类中value设计成volatile的原因是,因为多个线程之间这个value必须要共享的才行,因为Unsafe调用CAS算法的时候要把value当初参数传进去。

    2.Unsafe类

       Unsafe类提供了硬件级别的原子操作,Unsafe类中的方法都是native方法。

       Unsafe类:Unsafe提供的API大致可分为内存操作、CAS、Class相关、对象操作、线程调度、系统信息获取、内存屏障、数组操作等几类.

      

    3.Unsafe类的简单使用的问题

       我们也写一个类似的AtomicLong的类来实现自增的功能。

       

    启动直接报错:

    跟着这个错误我们可以找到,当加载我们自定义的这个类的时候,使用的是我们的应用程序类加载器AppClassLoador。而这里做了一个校验类加载器是为了只能让引导类加载器来加载这个Unsafe类。我们在深入理解Java虚拟机第七章里面说过,如果想把一个类交给引导类来加载,则需要使用null去替代ClassLoader.

    这么做的目的是Unsafe类可以直接操作内存,如果让应用程序类加载器来加载,势必不安全。

    4.那么我们怎么使用这个Unsafe类呢?

      我一开始想的是使用引导类加载器来加载自定义的这个类,利用类加载的传到规则不就可以使用启动类来加载这个Unsafe类吗,但是试了几次没有成功,换一种方式,利用反射,利用反射去获得这个实例。

      我们可以观察到  Unsafe将获取到的这个实例放到了这个属性中,我们就可以利用反射拿到这个实例

     

    再次启动之后从0变成了1

    看完这个例子之后我们再来总结一下CAS算法,就是通过变量在实例中的内存偏移量拿到这个变量在内存中此时此刻的值,如果与之前拿到这个变量的旧值相等,说明没有线程对他做修改,可以修改成我们期待的新值。

    JDK8以后的优化

    在竞争比较激烈的情况下,AtomicLong 还是又性能的问题,因为CAS一次只能有一个线程能修改成功,其他的线程会进入自旋状态。

    JDK8提供了高性能的LongAdder类,他就是解决高并发下性能问题的,他维护了一个基值变量base,和一个Cell数组,当高并发时,会有多个Cell变量来分担线程的竞争压力。最后的值等于基值base加上各个cell的值。

     Cell的结构:Cell结构里面也是用到了validate和CAS,用来保证当前线程跟新是被分配Cell中value的原子性

    LongAccumulator类

    可以自定去定义这个双目运算的接口

  • 相关阅读:
    操作系统学习笔记-精简复习版
    python和go执行字符串表达式
    Dubbo 获取本地ip错误
    软件测试人员提问常用的ChatGPT通用提示词模板
    K8S | Service服务发现
    基于Springboot宠物医院管理系统
    树 —— 树和森林的遍历
    web前端期末大作业基于html+css+javascript+jquery制作家乡主题风景网页设计与实现——张家口
    【JS进阶】纯函数 + 高阶函数 + 函数柯里化
    B2B独立站怎样将客户转化为订阅会员
  • 原文地址:https://blog.csdn.net/weixin_37650458/article/details/126534689