JMM

章三 JMM

本文是JVM系列第三篇,主要描述java内存模型,包括原子操作、指令重排序、可见性、有序性等相关内容,是java并发编程核心原理与基础

JMM是java提供的抽象模型,描述了在多线程环境中,主内存工作内存的交互,主要目标是屏蔽硬件和操作系统的差异。

  • 主内存:主内存用来存储所有共享变量
  • 工作内存:线程独享内存,类似cpu缓存,线程从主内存读取共享变量到工作内存,或者将修改后的数据回写到主内存
  1. 内存模型特性

    • 原子性:原子性表示一个操作不可分割,线程无法观察到其执行过程的中间态。例如基本变量的赋值(int a=10),通过synchronized或atomic实现的操作
    • 可见性:可见性表示线程多共享变量的修改对其他线程可见,例如使用volatile、synchronized、final关键字修饰
    • 有序性:有序性表示代码的执行顺序符合程序的逻辑顺序,但由于编译器和cpu的优化,实际执行顺序可能与代码顺序不一致(又称为指令重排序
  2. 关键概念

    • 主内存和工作内存的交互
      • lock:作用于主内存,将变量标记为线程独占状态
      • unlock:作用于主内存,解除某个内存地址的锁
      • read:从主内存读取共享变量
      • load:加载到工作内存
      • use:工作内存中使用变量
      • assign:修改变量
      • store:变量回写到主内存
      • write:将存储的值写回到主内存 ``` 补充说明:
      1. lock和unlock通常是原子性操作
      2. read/load和store/write:单次操作通常是原子性,例如32为的普通变量在jvm实现中读取和写入是原子操作。 64位的long和double类型变量在非volatile修饰是,read/write由于可能会分为两个32位块操作,导致非原子性
      3. use/assign,对变量执行简单的赋值是原子型的,但 i++/i--非原子性
      4. 多个内存组合操作通常不保证原子性 例如: int i=0; i++; 操作等价: a) read i:从主内存读取i b) load i:将i加载进工作内存 c) use i: 使用i值 d) assign i+i: 计算并重新赋值i==1 e) store i: 将新值存储到主内存 f) write i: 写会主内存

    ```

    • happens-before 原则:happens-before是jmm的核心规则,定义两个操作之间的顺序关系,如果A操作 happens-before B操作,那么A操作的结果对B操作可见
      • 程序顺序原则:单线程中,前面的操作happens-before后面的操作
      • 锁规则:一个程序释放锁,happens-before另一个线程获取锁
      • volatile:对一个volatile变量的写操作happens-before之后的操作
      • 线程启动规则:线程A调用线程B的start方法,happens-before线程B的执行
      • 线程终止规则:线程B的终止happens-before线程A通过Thread.join()等方法获知线程B的终止
  3. 指令重排序

    • 原因

      • 编译器优化:提高代码执行效率
      • 处理器优化:cpu使用乱序来提高流水线利用率
    • 影响:指令重排序可能导致程序在多线程环境下执行结果与预期不同

      class Singleton {
         private static Singleton instance;
      
         public static Singleton getInstance() {
              if (instance == null) { // 第一次检查
                   synchronized (Singleton.class) {
                     if (instance == null) { // 第二次检查
                       instance = new Singleton();
                     }
                  }
              }
           return instance;
        }
      }
      instance = new Singleton() 包含以下步骤:
       分配内存
       初始化对象;
       将引用指向对象。
      重排序可能导致步骤 2 和步骤 3 交换,其他线程可能访问未完全初始化的对象。
  4. volatile: java并发编程中的轻量同步机制,仅用来保证可见性和禁止重排序

    • 内存屏障:
      • 写屏障:在写操作前插入,确保写操作前的指令不被重排序到屏障后
      • 度屏障:在读操作后插入,确保读操作后的指令不会重排序到屏障前
    • volatile保证线程从主内存读取最新值,并将修改立刻写回到主内存
      • 普通变量:线程可能从工作内存中读取缓存的旧值
      • volatile:线程总是从主内存读取最新值,避免数据不可见问题
    • 局限:
      • 不保证原子性:虽然保证了可见性,但不能保证复合操作的原子性,例如i++涉及多个内存操作
      • 适用场景有限:只适用于状态标志、简单读写等场景,复杂线程安全问题仍需要synchronized或lock、Atomic

        本文由博客一文多发平台 OpenWrite 发布!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值