Java内存模型全解析:解决共享变量可见性与指令重排难题

本期说一下Java 内存模型(Java Memory Model,JMM)及共享变量可见性问题。

JMM是什么?

答:

Java 内存模型(Java Memory Model,JMM)抽象了线程和主内存之间的关系就比如说线程之间的共享变量必须存储在主内存中,规定了从 Java 源代码到 CPU 可执行指令的这个转化过程要遵守哪些和并发相关的原则和规范.

什么是共享变量的可见性?

答:

在多线程环境中,一个线程对共享变量的修改可能对其他线程是不可见的。这是因为每个线程有自己的工作内存,线程对变量的修改首先发生在工作内存中,然后被刷新到主内存。其他线程在读取该变量时直接从自己的工作内存中读取,而不是从主内存中读取。

JMM解决共享变量可见性问题的机制

答:

1.主内存与工作内存。

  1. volatile关键字。作用如下:

    • 用于实现内存屏障(Memory Barrier):

      • volatile关键字在读和写操作前后会插入内存屏障,也称为内存栅栏。内存屏障可以分为读屏障和写屏障。

      • 在写入volatile变量时,写屏障会确保所有之前的写操作都完成,然后再执行当前的写操作。这样可以防止指令重排序,确保写操作的原子性。

      • 在读取volatile变量时,读屏障会确保当前线程看到的是最新的值,而不是之前被其他线程修改但还未刷新到主内存的值。

      • 拓展:如果操作 A happens-before 操作 B,那么 A 的执行结果对于 B 是可见的,即 B 能够感知到 A 的影响。volatile关键字可以确保happens-before关系,即对一个volatile变量的写操作先于后续的读操作。

    • 禁止指令重排序

      • volatile关键字禁止编译器和处理器对被其修饰的变量进行一些优化,特别是在不影响程序正确性的前提下,防止重排序。这意味着volatile变量的写操作必须在读操作之前发生。
    • 使用CPU屏障指令:

      • 在底层,volatile关键字会使用一些CPU屏障指令来确保内存操作的顺序性。这些指令会告诉CPU在执行指令时要注意内存的一致性。
    • 缓存一致性协议:

      • 当一个线程写入volatile变量时,会通知其他线程该变量的值已经发生变化,从而保证了各个线程的缓存都是最新的。
  2. 使用锁机制

(如 synchronized 或 java.util.concurrent 包中的锁ReetrantLock)也能保证可见性。当一个线程获取锁时,它会清空工作内存中的变量,并重新从主内存中读取。

什么事指令重排?

答: 编译器和处理器为了提高性能可能对指令进行重排序。在单线程环境中,指令重排是允许的,因为它不会影响程序的最终执行结果。然而,在多线程环境中,指令重排可能导致共享变量的可见性问题,即一个线程对共享变量的修改对其他线程来说不可见,从而破坏了程序的正确性。

哪些情况会出现指令重排?

答:

  • 编译器优化:编译器(包括 JVM、JIT 编译器等)在不改变单线程程序语义的前提下,重新安排语句的执行顺序。
  • 处理器优化: 处理器在执行指令时也会进行一些优化,包括指令重排。处理器可能通过乱序执行等技术来提高指令执行的效率。

解决指令重排的方法有哪些?

答:

  • 使用 volatile 关键字修饰的变量,对该变量的写操作会在写操作之后插入一个写屏障,确保写操作的结果对其他线程是可见的。同时,对 volatile 变量的读操作会在读操作之前插入一个读屏障,防止在读操作之前的写操作被重排到读操作之后。

    • 屏障是一种硬件或软件机制,用于确保内存操作的顺序性和可见性。
  • 使用Synchronized或ReentrantLock解决指令重排

    • 锁的释放和获取会创建一个内存屏障(比如Synchornize中的monitorenter和monitorexit),确保了在释放锁之前的所有写操作都被刷新到主内存,而在获取锁之后的读操作都从主内存中重新加载。
      • 注:reentrantlcok的内存屏障的实现,利用了 volatile 变量、CAS 操作和 LockSupport 等底层机制,以确保在锁的获取和释放操作之间的内存可见性和有序性。
  • 使用final字段解决指令重排问题

    • 当一个字段被声明为 final 时,Java 编译器会确保在构造函数完成之前,final 字段的赋值操作已经完成。这就意味着其他线程在构造函数未完成之前无法看到对象的不完整状态,包括未完成的初始化。

    以上内容出自本人整理的面试秘籍。 链接: https://pan.baidu.com/s/1o014Ems8diV0D3h8K15olA?pwd=fi3x 提取码: fi3x 复制这段内容后打开百度网盘手机App,操作更方便哦

工作日每天更新,周末随缘更新。

请关注我,以便及时获取最新内容哦!

本文由 mdnice 多平台发布

  • 13
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值