首页 > 系统相关 >Java内存模型全解析:解决共享变量可见性与指令重排难题

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

时间:2024-07-24 17:29:14浏览次数:18  
标签:Java 变量 指令 线程 内存 重排 volatile 操作

本期说一下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 字段的赋值操作已经完成。这就意味着其他线程在构造函数未完成之前无法看到对象的不完整状态,包括未完成的初始化。

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

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

本文由 mdnice 多平台发布

标签:Java,变量,指令,线程,内存,重排,volatile,操作
From: https://blog.csdn.net/zwsfamily/article/details/140668546

相关文章

  • Java基础——String/StringBuilder/StringBuffer区别
    四个方面:不可变性、线程安全、性能、使用场景String:不可变,线程安全,适用于多线程编程。注意:由于String内部字符数组由final修饰,对其进行改变时会创建新的String对象,旧的会被JVM回收,容易触发gc(垃圾回收),这种行为可能会导致频繁的内存分配和垃圾回收,从而引起系统的内存抖动(memor......
  • java基础语法
    Java基础语法编译与运行在终端运行编译javajava文件,会生成一个class文件运行class文件,javaclass文件publicclassHello{ //类(publicclass)+名称(Hello)publicstaticvoidmain(String[]args){ //修饰符/关键字(publicstaticvoid)+方法(main)+参数S......
  • 关于内存条选择的一些看法
    先叠甲,只是个人看法以及近期学的知识,欢迎大家讨论,我的知识面也不够全面电脑的内存条分为DDR4与DDR5需要与主板的卡槽对应,挑选需要关注三个核心:容量,频率,参数。先说一下容量,内存条的容量的选择关乎于你的日常工作量,需不需要多开各类办公软件,以及你玩什么类型的游戏,容量越大越流畅......
  • Java中string对象是如何实现的?string对象的优化过程
    1.基本实现Java中的String类是一个final类,这意味着它不能被继承。它内部使用一个字符数组(char[])来存储实际的字符序列。这个字符数组是私有的,并且不能被外部直接访问或修改(除了通过String类提供的公共方法)。String类还包含一些字段来跟踪字符串的长度(value.length)和哈希......
  • java代审中对jar包的审计
    在代码审计中,java比较特殊,相比于php这种纯脚本文件驱动,java还可以使用内置虚拟机驱动(如比较新的spring技术),这就常常涉及到jar包。之前都是跳过jar包,以为jar包里面就是一些框架性的东西,但是其实,有些jar包就是作者为系统专门编写或修改的,其中被引用的方法也是可能被直接引用,所以......
  • Java学习笔记(三)算术运算符、逻辑运算符、四种进制介绍
    Hii,mJinXiang⭐前言⭐本篇文章主要介绍Java算术运算符、逻辑运算符、四种进制介绍详细使用以及部分理论知识......
  • JavaScript 基础知识
    JavaScript是一种编程语言,可为您的网站增加交互性。这发生在游戏中,在按下按钮或在表单上输入数据时的响应行为中;具有动态样式;带有动画等。本文可帮助您开始使用JavaScript,并进一步了解可能的情况。什么是JavaScript?JavaScript 是一种功能强大的编程语言,可以为网站......
  • Java学习笔记(七)面向对象编程(中级部分)
    Hii,mJinXiang⭐前言⭐本篇文章主要介绍Java面向对象编程(中级部分)包、访问修饰符、封装、继承、super关键字、多态、向上(下)转型、equals、hashCode、断点调试等知识的详细使用以及部分理论知识......
  • 学习Java的日子 Day56 数据库连接池,Druid连接池
    Day561.数据库连接池理解:池就是容器,容器中存放了多个连接对象使用原因:1.优化创建和销毁连接的时间(在项目启动时创建连接池,项目销毁时关闭连接池)2.提高连接对象的复用率3.有效控制项目中连接的个数(连接对象占内存资源)数据库连接池负责分配、管理和释放数据库连接......
  • Java 内存模型
    Author:ACatSmilingSince:2024-07-24概念Java内存模型:JavaMemoryModel,简称JMM,是Java语言中定义的一组规则和规范,用于解决多线程环境下的内存可见性和有序性问题。JMM确定了线程之间如何通过内存进行交互,并规定了变量的读取和写入操作的行为。JMM能干吗?通过JMM来......