• 07JVM_内存模型和CAS与原子类


    一、内存模型

    1.java内存模型

    Java内存结构JMM(Java Memory Model)的意思。JMM定义了一套在多线程读写共享数据(成员变量,数组)时,对数据原子性,见性,有序性的规则和保障。

    1.1 原子性

    什么是原子性?

    原子性是指一个操作是不可中断的,即使多个线程一起执行,一个线程一旦开始,就不会被其他线程干扰。

    如何保证原子性

    synchronized(同步关键字)

    1. synchronized(对象){
    2.   原子操作代码
    3. }

    从第一个线程开始,给这个对象加,可以安全执行原子操作代码。其他线程需要排队等候

    synchronized解决并发问题

    ②各种Lock

    synchronized 和各种 Lock 可以保证任一时刻只有一个线程访问该代码块,因此可以保障原子性

    1.2 可见性

    什么是可见性?

    可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。

    如何保证可见性

    在 Java 中,可以借助synchronized、volatile 以及各种 Lock 实现可见性。如果我们将变量声明为 volatile ,这就指示 JVM,这个变量是共享且不稳定的,每次使用它都到主存中进行读取。

    volatile

    修饰成员变量和静态成员变量,避免线程从自己的工作缓存查找变量的值,必须到主存获取它的值,线程操作volatile变量都是直接操作主存

    1.3有序性

    什么是有序性?

    ①由于指令重排序问题,代码的执行顺序未必就是编写代码时候的顺序。

    ②指令重排序可以保证串行语义一致,但是没有义务保证多线程间的语义也一致 ,所以在多线程下,指令重排序可能会导致一些问题。

    ③在Java中,volatile关键字可以禁止指令进行重排序优化

    2.happens-before

    介绍

    happens-before规定哪些写操作对其他线程的读操作可见。是可见性有序性的一套规则。

    如何保证

    ①volatile

    ②synchronized

    二、CAS与原子类

    1.CAS无锁并发概述

    1.介绍

    ①CAS全称compare and swap比较并交换

    ②当多个线程同时操作同一个资源,只能有一个线程操作成功。但是不会阻塞其他线程,其他线程只会收到操作失败的信号。

    ③CAS是一个乐观锁

    补充

    乐观锁:认为数据在一般情况下不会产生冲突,所以在数据提交更新的时候,才会对数据是否产生并发冲突进行检测,如果发现并发冲突,则返回错误信息,返回的错误信息可以根据自己的业务进行处理

    悲观锁:总是假设最坏的情况,每次在获取共享数据的时候,都认为别人会修改,所以每次都在获取数据的时候加锁。共享资源每次只会给一个线程使用,其他线程阻塞,用完再把资源给其他线程

    2.工作流程

    读写的内存值V

    进行比较的值A

    需要写入的新值B

    ①内存中的原数据V,旧值A,修改的新值B。

    比较A与V是否相等

    ③如果相等,将B写入V(交换)

    ④返回操作是否成功

    3.代码分析

    多个线程对一个共享的整型变量执行+1操作

    ①CAS不加锁,使用while(true)死循环不管尝试/

    共享变量是从内存读取的,所以保证变量的可见性。使用volatile修饰

    ③调用compareAndSwap(旧值,新值)进行比较。

    ④compareAndSwap操作成功退出循环。

    ⑤compareAndSwap操作失败,说明其他线程把这个共享变量修改了。需要再次循环读取

    注意:

    ①CAS和volatile结合实现无锁并发,适用竞争不激烈多核CPU(循环重试)

    ②竞争激烈,重试频繁发生,降低效率

    ③没有使用用synchronized,线程不会阻塞,提升效率。

    4.CAS的缺点

    ABA问题,CAS更新操作的时候检查内存值是否变化,没有变化更新内存值。如果原来内存值A,后来变成B,然后再变回A。出现ABA问题,CAS检查没有变化,实际变化了。解决方法就是变量前面加一个版本号,每次更新版本号加1。这样变化成了1A2B3A

    ②循环时间长,开销大。CAS操作长时间不成功,会导致一直循环。CPU开销大

    ③只保证一个共享变量的原子操作。对一共享变量执行操作时,CAS能够保证原子操作,但对多个共享变量操作时,CAS无法保证操作的原子性。

    2.CAS底层实现

    介绍

    CAS底层是依赖一个Unsafe直接调用操作系统底层的CAS指令。

    调用UnSafe类中的CAS方法,JVM会帮我们实现出CAS汇编指令

    部分代码

    1. public final boolean compareAndSet(int expect, int update) {
    2.         return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    3. }

    参数说明

    this Unsafe对象

    valueOffset 共享变量的地址

    expect 旧值

    update 新值

    如果原子变量中的 value 值等于 expect,则使用 update 值更新该值并返回 true,否则返回 false。

    3.原子操作类

    juc提供原子操作类,可以提供线程安全的操作。AtomicInteger,AtomicBoolean。底层实现是CAS+volatile实现

  • 相关阅读:
    代码随想录2.5——数组:904水果成篮、76最小覆盖子串
    2023NOIP A层联测6 数点
    【CPP】slt-list由认识到简化模拟实现深度理解~
    SpringCloud Alibaba微服务实战四 - 限流熔断
    mybatis-3.5.0使用插件拦截sql以及通用字段赋值
    十大排序(上)
    conda虚拟环境安装pytorch(gpu版本)纪实
    二维数组——onenote笔记
    解开MongoDB之谜
    计算机毕业设计Java便捷式管理系统(源码+系统+mysql数据库+lw文档)
  • 原文地址:https://blog.csdn.net/jbkjhji/article/details/132905963