【并发编程】深入理解Java内存模型及相关面试题

news2024/11/14 22:53:10

文章目录

    • 优秀引用
    • 1、引入
    • 2、概述
    • 3、JMM内存模型的实现
      • 3.1、简介
      • 3.2、原子性
      • 3.3、可见性
      • 3.4、有序性
    • 4、相关面试题
      • 4.1、你知道什么是Java内存模型JMM吗?
      • 4.2、JMM和volatile他们两个之间的关系是什么?
      • 4.3、JMM有哪些特性/能说说JMM的三大特性吗?
      • 4.4、为什么要有JMM,它为什么会出现,作用和功能是什么
      • 4.5、有了解过happens-before原则吗?

优秀引用

全面理解Java的内存模型(JMM)

终于有人把Java内存模型(JMM)说清楚了

1、引入

对于Java虚拟机的内存模型相信大家都不陌生了,对于每一个线程来说,栈是私有的,而堆是共享的,也就是说在栈中的变量(局部变量、方法定义参数、异常处理器参数)不会在线程之间共享,也就不会有内存可见性的问题,也不受内存模型的影响。

img

既然堆中的数据是线程共享的,那么一定会存在一个并发问题,但由于每个线程都有自己的本地缓存,导致线程之间读取的数据可能不是最新的,从而出现数据不一致的问题。JMM定义了一种内存模型,用于描述Java程序中多线程之间如何访问共享内存中的变量,从而解决了这个问题。

这里扯一嘴,在Java中使用的是共享内存并发模型,用于解决Java中线程间如何通信和数据同步的问题。

2、概述

JMM(Java Memory Model)是Java内存模型的缩写,是一种抽象的概念,定义了Java虚拟机如何在计算机内存中存储和访问Java对象的方法。JMM规范主要用于解决多线程访问共享内存时的可见性、有序性和原子性问题。下面是JMM的抽象示意图:
JMM抽象示意图

从上图中可以看出:

  • 所有的共享变量都存在主内存中;

  • 每个线程都保存了一份该线程使用到的共享变量的副本

  • 如果线程A与线程B之间要通信的话,必须经历下面2个步骤:

    1. 线程A将本地内存A中更新过的共享变量刷新到主内存中去。

    2. 线程B到主内存中读取线程A之前已经更新过的共享变量。

因此,线程A无法直接访问线程B的工作内存,那是因为工作内存是线程独有的,线程间通信必须借助主内存,这也是JMM中的规定。当主内存中的共享变量被某个线程更新时,JMM会通过控制主内存与每个线程的本地内存之间的交互,来提供内存可见性保证。因此通过JMM规范,有效的解决了以下问题:

  • 可见性问题:JMM保证对于一个线程对变量的修改,其他线程能够立即看到这个修改,从而避免了线程之间读取数据不一致的问题;
  • 有序性问题:JMM保证程序的执行顺序是有序的,即按照代码的编写顺序执行,从而避免了出现代码执行顺序混乱的问题;
  • 原子性问题:JMM保证对单个变量的读取和写入操作是原子性的,即不会出现数据竞争问题。

3、JMM内存模型的实现

3.1、简介

在Java中存在着许多并发相关的关键字,如valatile、synchronized、final等,而这些被大众所熟知的关键字便是Java内存模型封装了底层的实现后提供给开发人员进行使用。因此Java内存模型除了定义了一套规范,还提供了一系列的封装了底层实现的关键字供开发者使用。

3.2、原子性

原子性指的是指一个操作是不可中断的,即多线程环境下,操作不能被其他线程干扰。在Java中,最常用的便是使用关键字synchronized进行原子性的保证。

3.3、可见性

指当一个线程修改了某一个共享变量的值,其他线程是否能够立即知道该变更。对于Java中的普通共享变量是不保证可见性的,因为数据修改被写入内存的时机是不确定的,多线程并发下很可能会出现脏读的并发问题,因此便有着上面提及到的线程私有的工作内存

每个线程的工作内存都保存了一份该线程使用到共享变量的副本,即主内存中的拷贝副本,在操作数据时只能在本地的副本中进行操作,不能直接对主内存中的数据进行操作。同时不同线程间也是不能直接进行通讯的,必须借助主内存来实现。

而在Java中提供了volatile、synchronized、final关键字来保证多线程操作时变量的可见性,其中volatile关键字提供了这么一个功能,那就是被其修饰的变量在被修改后可以立即同步到主内存中,被其他修饰的变量在每次使用之前都从主内存中刷新获取,从而保证可见性。

3.4、有序性

指程序是有序的按照一定的顺序运行,这一特性主要是针对于操作系统中对程序指令进行重排序造成的并发乱序问题。为了性能和便捷,在JMM中指明,再不改变程序执行结果的前提下,允许编译器和处理器对程序优化进行重排序。

在Java中,可以使用synchronizedvolatile来保证多线程之间操作的有序性。实现方式有所区别:

  • volatile关键字会禁止指令重排;
  • synchronized关键字保证同一时刻只允许一条线程操作。

值得注意的是,按照一定的顺序并不一定是代码中的顺序,典型的例子便是线程的创建和执行,下面的示例代码便是先执行第四行后执行第二行:

Thread t1 = new Thread(() -> {
  System.out.println("hello thread");
}, "t1");
t1.start();

4、相关面试题

4.1、你知道什么是Java内存模型JMM吗?

JMM(Java内存模型)是Java虚拟机规范中定义的一种内存模型,用于描述Java程序中多线程之间如何访问共享内存中的变量。JMM规定了Java程序中的所有变量都存储在主内存中,每个线程都有自己的本地缓存,线程对变量的读取和写入操作都必须在本地缓存和主内存之间进行同步,以保证数据的可见性、原子性和有序性。

JMM定义了一些规则和约束,如volatile关键字、synchronized关键字等,用于保证程序的正确性和稳定性。使用volatile关键字可以保证变量的可见性,即每个线程都能看到其他线程对该变量的最新修改。使用synchronized关键字可以保证代码块的原子性,即同一时刻只有一个线程能够执行该代码块。

4.2、JMM和volatile他们两个之间的关系是什么?

volatile是对JMM底层实现封装的关键字之一,是JMM的一种实现方式,用于修饰变量,表示该变量是可见性的,即任何对该变量的修改都会立即被其他线程所看到。volatile关键字是JMM的一种实现方式,它可以保证变量的可见性。

在Java中,使用volatile关键字修饰的变量会被存储在主内存中,每个线程访问该变量时都会从主内存中读取最新的值,而不是从线程的本地缓存中读取。因此,使用volatile关键字可以保证变量的可见性,避免出现数据不一致的问题。

同时,volatile关键字还具有禁止指令重排序的作用,即保证代码的有序性。由于JMM规定了线程之间的操作可能会存在重排序的情况,因此使用volatile关键字可以禁止指令重排序,保证程序的正确性和稳定性。

4.3、JMM有哪些特性/能说说JMM的三大特性吗?

JMM(Java内存模型)有三个特性,也被称为JMM的三大特性,分别是原子性、可见性和有序性。

  1. 原子性:原子性是指对于单个变量的读取和写入操作是原子性的,即不会出现数据竞争问题。在JMM中,原子性是通过synchronized关键字和volatile关键字来保证的。
  2. 可见性:可见性是指当一个线程对一个变量进行修改时,其他线程能够立即看到这个修改,从而避免了线程之间读取数据不一致的问题。在JMM中,可见性是通过volatile关键字来保证的。
  3. 有序性:有序性是指程序的执行顺序是有序的,即按照代码的编写顺序执行,从而避免了出现代码执行顺序混乱的问题。在JMM中,有序性是通过happens-before规则来保证的。

happens-before规则定义了程序执行中各个操作之间的偏序关系,主要述说的是,某一段符合该规则的代码,前面代码得到的结果肯定对后方代码是可见的。

4.4、为什么要有JMM,它为什么会出现,作用和功能是什么

在Java多线程编程中,由于多个线程之间共享数据的情况很常见,因此需要一种机制来保证多线程之间的数据访问是正确的。在JVM中,由于每个线程都有自己的本地缓存,因此线程之间读取的数据可能不是最新的,从而出现数据不一致的问题。为了解决这个问题,Java引入了JMM。

JMM的作用就是规定了一些规则,保证多线程访问共享变量的正确性。JMM主要有以下几个功能:

  1. 确定共享变量的可见性:JMM规定,如果一个线程修改了共享变量的值,其他线程必须能够立即看到这个变化。
  2. 确定操作的有序性:JMM规定,如果一个线程对共享变量进行了多次修改,其他线程必须按照这些修改的顺序来看到这些变化。
  3. 确定操作的原子性:JMM规定,如果一个线程在修改共享变量的过程中,其他线程必须等待这个修改完成后再进行操作。

4.5、有了解过happens-before原则吗?

happens-before原则是Java内存模型中一个重要的概念,用于指定多线程程序中操作之间的顺序关系。

happens-before原则规定,如果操作A happens-before操作B,那么操作A的效果在操作B之前对其他线程是可见的。也就是说,如果在一个线程中操作A happens-before操作B,那么在另一个线程中看到操作A的效果一定是在看到操作B的效果之前。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/399784.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从新手小白到运维大咖,SysOM 多场景宕机实例解析 | 龙蜥技术

文/刘馨蔚,系统运维 SIG Contributor “老板老板,今天业务又发生了抖动,具体原因暂时还不能快速查清,再给我点时间吧。” “老板老板,这个问题我好像解过,但是也不太确定,我再重新分析一次吧。…

Django/Vue实现在线考试系统-05-开发环境搭建-PyCharm安装

1.0 PyCharm下载和安装 PyCharm 是 JetBrains 公司(www.jetbrains.com)研发,用于开发 Python 的 IDE 开发工具。图 1 所示为 JetBrains 公司开发的多款开发工具,其中很多工具都好评如潮,这些工具可以编写 Python、C/C++、C#、DSL、Go、Groovy、Java、JavaScript、Objecti…

关于kafka,你背了哪些面试题(持续更新中)

昨天面试大数据开发岗位,面试官问了一个开放性的问题,讲讲你对kafka的认识,一下有些懵住,不知道从哪里开始谈起。 今天和另外一个大佬聊天,他告诉我,就是要背面试题,背面试题是一种有效的学习方…

如何把iPhone照片导入电脑?图文教学,1分钟教你快速导入

​在日常生活中,我们经常会用iPhone拍摄照片,但是iPhone的存储空间有限,随着照片的增加,存储空间会越来越少。因此,把iPhone照片导入电脑成为了很多人需要解决的问题。那么,如何把iPhone照片导入电脑呢&…

Linux上安装配置ZooKeeper

Linux上安装配置ZooKeeper 下载压缩文件 将压缩文件拷贝到指定目录下 执行命令 tar -zxvf [apache-zookeeper-3.5.7-bin.tar.gz] -C [/opt/module/]注:第一个括号里面是压缩文件名称,第二个括号里面是解压到指定的目录 进入到解压后的文件夹当中&am…

KDHG-A变频互感器综合测试仪

一、概述 KDHG-A电流互感器现场综合测试仪是一种专门为测试互感器:伏安特性、变比、极性、误差曲线、计算拐点和二次侧回路检查等设计的多功能现场试验仪器。 二、主要特点 1.单机220V输入时最大电压输出0-2500V,单机最大电流输出0-1000A&am…

我的同事用PicSo AI这款绘画软件,连夜生成了100个“女朋友”

最近的AI绘画实在是太火爆了! 有人用它来生成商业插画,有人用它来测试AI的智商,有人用它来为小说生成配图,有人在它的作品中寻找灵感… 而我的同事,用AI软件给自己画了将近100个漂亮的女朋友! 而这款令…

美颜SDK关键技术讲解——人脸识别与人脸美化

拍摄,自从智能手机普及之后就已经不再是小众爱好,使用手机拍摄记录生活几乎成了人们的日常。在巨量的需求下,美颜工具、美颜SDK已经被广泛应用于各大视频拍摄平台。虽然经常听到美颜SDK,但是大多数人并不了解它,下文小…

【量化交易笔记】4.移动平均值的实现

上一讲已经讲A股的数据下载到本地或保存数据库,我们可以随时使用。 移动平均MA(Moving Average) ,是用统计分析的方法,将一定时期内的证券价格(指数)加以平均,并把不同时间的平均值连接起来,形成…

Git 分支管理常用指令

不同分支有着自己的工作区和本地仓库,相互之间看不到,也影响不到,只有在合并分支的时候,才会将某一个分支做出的修改更新到另一个分支上。 目录 1、git branch(分支查看、创建、删除) (1) 查看分支 (2) …

园区网双出口问题解决方案

园区网双出口拓扑图公司向运营商租⽤两条带宽,ISP1为100M,ISP2为50M,默认情况下园区⽤户访问Internet优先⾛ISP1链路,请提供解决⽅案。解决方案1:接入路由为静态时解决方案2:当接入为动态路由时解决方案3&a…

荣耀MagicBook电脑系统损坏怎么U盘重装系统?

荣耀MagicBook电脑系统损坏怎么U盘重装系统?有用户电脑开机之后,无法正常进入桌面了,而是变成了一个蓝屏的界面。通过重启和进行系统修复都没有用。这个情况只有去进行U盘重装系统了。接下来我们就来看看以下详细的重装系统方法教学吧。 准备…

Python之函数参数细讲

文章目录前言一、了解形式参数和实际参数1. 通过作用理解2. 通过一个比喻来理解形式参数和实际参数二、位置参数1. 数量必须与定义时一致2. 位置必须与定义时一致三、关键字参数四、为参数设置默认值五、可变参数1. *parameter2. **parameter总结前言 在调用函数时,…

Spark MLlib概述

Spark MLlib概述机器学习房价预测模型选型数据探索数据提取准备训练样本模型训练模型效果评估机器学习 机器学习的过程 : 基于历史数据,机器会根据一定的算法,尝试从历史数据中挖掘并捕捉出一般规律再把找到的规律应用到新产生的数据中,从而…

【拜占庭将军问题】这一计谋,可以让诸葛丞相兴复汉室

我们都知道,诸葛亮第一次北伐是最可能成功的,魏国没有防备,还策反了陇西,陇西有大量的马匹可以装备蜀国骑兵,可惜街亭一丢,那边就守不住了 当时我不在,只能作诗一首~ 如果穿越过去,…

SpringBoot下的Spring——DAY04——动态代理总结、AOP、自定义注解进行拦截、动态获取注解参数、通知方法(内含源代码)

SpringBoot下的Spring——DAY04——动态代理总结、AOP、自定义注解进行拦截、动态获取注解参数、通知方法(内含源代码) 源代码下载链接地址:https://download.csdn.net/download/weixin_46411355/87549575 目录SpringBoot下的Spring——DAY0…

【点云学习】多时相激光雷达点云

多时相雷达数据(multi-tempral LiDAR data) 1 一种多时相激光雷达数据建筑物变化检测方法-汪承义(2013) 背景:空间分辨率的提高引入了“类内可分性”增加与“类间可分性”降低;遮挡与阴影的存在使问题变得…

pytorch权值初始化和损失函数

pytorch权值初始化和损失函数 权值初始化 梯度消失与爆炸 针对上面这个两个隐藏层的神经网络,我们求w2的梯度 可以发现,w2的梯度与H1(上一层网络的输出)有很大的关系,当h1趋近于0时,w2的梯度也趋近于0&am…

swoole的强大之处,你可能只是略知一二!

首先 swoole 是 php 的一个扩展程序swoole 是一个为 php 用 c 和 c 编写的基于事件的高性能异步 & 协程并行网络通信引擎swoole 是一个多进程模型的框架,当启动一个进程 swoole 应用时,一共会创建 2nm 个进程,n 为 worker 进程数&#xf…

maven将jar文件上传至本地仓库及私服

maven官方仓库有些依赖并不存在&#xff0c;现在项目都是maven直接获取jar&#xff0c;当maven获取不到时&#xff0c;需要我们把jar上传至maven仓库。已 ImpalaJDBC41.jar 文件为例&#xff0c;如&#xff1a;希望上传后&#xff0c;设置的依赖为&#xff1a;<dependency&g…