并发编程系列【JMM模型与volatile关键字】(二)

什么是JMM模型?

  • 概念:Java 内存模型,Java Memory Model,是一种抽象概念或规范,并非实际存在
  • 主要规范了各变量的访问方式
  • JVM会为每个线程都创建一个工作内存(也可称为栈空间),用于存储私有数据
  • 而Java内存模型中还规定所有变量都存储在主内存,主内存是所有线程都可以共享访问的内存区
  • 但线程对变量的操作都必须在工作内存中完成,所以这中间会有一次内存拷贝和内存回写
  • 工作内存为每个线程私有数据区,线程间互不可见,必须通过主内存才可完成线程间数据通信
  • 当然,不管是工作内存数据还是主内存数据,实际都是存储在主内存中,也可能存储到CPU缓存或寄存器中
不同于JVM内存区模型
  • 两个属于不同层次的概念
  • JMM其实描述的是一组规则,围绕变量的原子性、有序性和可见性展开
  • JVM内存区划分是围绕程序执行过程中的堆、栈、程序计数器、方法区等概念
  • JMM描述的规则与JVM内存区有一些相似概念
  • 其实两者都属于是抽象的规范,是对内存区域的一种概念上的区分,并不实际存在

主内存与工作内存
  • 工作内存主要存储着主内存中部分数据的副本
  • 由上可知,工作内存所存储的数据是不存在线程安全问题的,但主内存中Gong享的数据存在

  • 举例:两个不同线程去操作同一个对象的同一个方法,都会将数据拷贝一份到自己的工作内存,操作完成后,将数据刷回到主内存
  • JMM与硬件内存架构的联系,其实是一种相互交叉关系

JMM存在的必要性
  • 两个线程同时对主存中的实例对象进行操作,可能诱发线程安全问题
  • 举例:共享变量x,AB两个线程,都对x操作,A将x=2,B来读x,此时B读到的是1还是2?不确定

  • 具体会是哪种情况发生,对应哪种结果?JVM定义了8大原子操作规范,成为两个内存之间的具体交互协议及实现细节
数据Sync八大原子操作
  1. lock,作用于主内存,将变量标记为独占状态
  2. unlock,作用于主内存,释放锁定变量,释放后才可被其他线程锁定
  3. read,作用于主内存,将值从主内存传输到工作内存
  4. load,作用于工作内存,把read过来的变量放入工作内存变量副本
  5. use,作用工作内存,将一个值传递给执行引擎
  6. assign,作用于工作内存,从执行引擎接Shou到的值赋给工作内存变量
  7. store,作用工作内存,把工作内存中的值传给主内存
  8. write,作用于工作内存,将store操作的变量值传递给主内存的变量
  • JMM要求从主存复制到工作内存,或从工作内存sync到主存,必须按顺序执行相关操作,但没要求必须连续执行

可见性、原子性与有序性问题
  • **原子性:**一个操作一旦开始,不可能被其他线程中断
  • **可见性:**一个线程修改了某个变量,另外线程是否可立马知道这个修改
  • **有序性:**对于单线程而言,本线程内可视为有序执行没毛病,但多线程环境可能出现乱序现象,因为指令重排机制的存在

单看一个线程内,所有操作可视为有序,若是多线程环境下,一个线程观察另一个线程,所有操作可能都是无序的,主要原因为指令重排现象加工作内存与主内存Sync延迟现象所致

如何解决?

  • 原子性:JVM除对基本数据类型读写操作实现了原子性外,可使用synchronized和Lock来实现,因为其能保证任意时刻只有一个线程访问该代码块
  • 可见性:volatile关键字,可保证其共享变量的可见性,即为当某个线程修改了该变量,其他线程可立即感知到
  • 有序性:volatile可一定程度的保证有序性,也可通过synchronized 或 Lock来保证

volatile 关键字

  • JVM提供的轻量级Sync机制,保证共享变量对所有线程总是可见的
  • 原理可简单理解为:变量每次在被访问时,都是从主内存中读改变量,而一旦发生变化,则强迫将最新的值刷到主存
  • 并且会禁止指令重排机制发生,关于这个,可以去深入了解下**【内存屏障】**概念
  • 无法保证原子性,例如在某个方法里对i++,多线程执行时可能存在线程安全问题,具体可以深入了解其原因

扩展了解DCL(单例的双重检测)

/**
 * @author qinchen
 * @date 2021/7/8 16:38
 * @description 单例模式下的双检锁学知识习
 */
public class DoubleCheckLock {

    private static DoubleCheckLock instance;

    public static DoubleCheckLock getInstance() {
        // 第一次检测
        if(instance == null) {
            // Sync代码块
            synchronized (DoubleCheckLock.class) {
                // 第二次检测
                if(instance == null) {
                    // 在多线程环境下,依然可能出现问题
                    instance = new DoubleCheckLock();
                }
            }
        }
        return instance;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值