【并发编程】深入理解Java内存模型及相关面试题
文章目录
- 优秀引用
- 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虚拟机的内存模型相信大家都不陌生了,对于每一个线程来说,栈是私有的,而堆是共享的,也就是说在栈中的变量(局部变量、方法定义参数、异常处理器参数)不会在线程之间共享,也就不会有内存可见性的问题,也不受内存模型的影响。
既然堆中的数据是线程共享的,那么一定会存在一个并发问题,但由于每个线程都有自己的本地缓存,导致线程之间读取的数据可能不是最新的,从而出现数据不一致的问题。JMM定义了一种内存模型,用于描述Java程序中多线程之间如何访问共享内存中的变量,从而解决了这个问题。
这里扯一嘴,在Java中使用的是共享内存并发模型,用于解决Java中线程间如何通信和数据同步的问题。
2、概述
JMM(Java Memory Model)是Java内存模型的缩写,是一种抽象的概念,定义了Java虚拟机如何在计算机内存中存储和访问Java对象的方法。JMM规范主要用于解决多线程访问共享内存时的可见性、有序性和原子性问题。下面是JMM的抽象示意图:
从上图中可以看出:
-
所有的共享变量都存在主内存中;
-
每个线程都保存了一份该线程使用到的共享变量的副本。
-
如果线程A与线程B之间要通信的话,必须经历下面2个步骤:
-
线程A将本地内存A中更新过的共享变量刷新到主内存中去。
-
线程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中,可以使用synchronized
和volatile
来保证多线程之间操作的有序性。实现方式有所区别:
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的三大特性,分别是原子性、可见性和有序性。
- 原子性:原子性是指对于单个变量的读取和写入操作是原子性的,即不会出现数据竞争问题。在JMM中,原子性是通过synchronized关键字和volatile关键字来保证的。
- 可见性:可见性是指当一个线程对一个变量进行修改时,其他线程能够立即看到这个修改,从而避免了线程之间读取数据不一致的问题。在JMM中,可见性是通过volatile关键字来保证的。
- 有序性:有序性是指程序的执行顺序是有序的,即按照代码的编写顺序执行,从而避免了出现代码执行顺序混乱的问题。在JMM中,有序性是通过happens-before规则来保证的。
happens-before规则定义了程序执行中各个操作之间的偏序关系,主要述说的是,某一段符合该规则的代码,前面代码得到的结果肯定对后方代码是可见的。
4.4、为什么要有JMM,它为什么会出现,作用和功能是什么
在Java多线程编程中,由于多个线程之间共享数据的情况很常见,因此需要一种机制来保证多线程之间的数据访问是正确的。在JVM中,由于每个线程都有自己的本地缓存,因此线程之间读取的数据可能不是最新的,从而出现数据不一致的问题。为了解决这个问题,Java引入了JMM。
JMM的作用就是规定了一些规则,保证多线程访问共享变量的正确性。JMM主要有以下几个功能:
- 确定共享变量的可见性:JMM规定,如果一个线程修改了共享变量的值,其他线程必须能够立即看到这个变化。
- 确定操作的有序性:JMM规定,如果一个线程对共享变量进行了多次修改,其他线程必须按照这些修改的顺序来看到这些变化。
- 确定操作的原子性:JMM规定,如果一个线程在修改共享变量的过程中,其他线程必须等待这个修改完成后再进行操作。
4.5、有了解过happens-before原则吗?
happens-before原则是Java内存模型中一个重要的概念,用于指定多线程程序中操作之间的顺序关系。
happens-before原则规定,如果操作A happens-before操作B,那么操作A的效果在操作B之前对其他线程是可见的。也就是说,如果在一个线程中操作A happens-before操作B,那么在另一个线程中看到操作A的效果一定是在看到操作B的效果之前。
相关文章:

【并发编程】深入理解Java内存模型及相关面试题
文章目录优秀引用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的三大特性吗?…...
C++编程语言STL之queue介绍
本文主要介绍C编程语言的STL(Standard Template Library)中queue(队列)的相关知识,同时通过示例代码介绍queue的常见用法。1 概述适配器(adaptor)是STL中的一个通用概念。容器、迭代器和函数都有…...
ACO优化蚁群算法
%% 蚁群算法(ant colony optimization,ACO) %清空变量 clear close all clc [ graph ] createGraph(); figure subplot(1,3,1) drawGraph( graph); %% 初始化参数 maxIter 100; antNo 50; tau0 10 * 1 / ( graph.n * mean( graph.edges(:) …...

SwiftUI 常用组件和属性(SwiftUI初学笔记)
本文为初学SwiftUI笔记。记录SwiftUI常用的组件和属性。 组件 共有属性(View的属性) Image("toRight").resizable().background(.red) // 背景色.shadow(color: .black, radius: 2, x: 9, y: 15) //阴影.frame(width: 30, height: 30) // 宽高 可以只设置宽或者高.…...
Centos 中设置代理的两种方法
Centos 中设置代理的两种方法 在使用局域网时,有时在局域网内只有一台电脑可以进行上网,其他电脑只能通过配置代理的方式来上网,在Windows系统中设置代理上网相对简单,如果只需上网的话,只需在浏览器中找到网络连接&am…...
高速PCB设计指南系列(一)
第一篇 PCB布线 在PCB设计中,布线是完成产品设计的重要步骤,可以说前面的准备工作都是为它而做的, 在整个PCB中,以布线的设计过程限定最高,技巧最细、工作量最大。PCB布线有单面布线、 双面布线及多层布线。布线的方…...

云端IDE:TitanIDE v2.6.0 正式发布
原文作者:行云创新技术总监 邓冰寒 引言 云原生集成开发环境 TitanIDE v2.6.0 正式发布了,一起来看看都有那些全新的体验吧! TitanIDE 是一款云IDE, 也称 CloudIDE,作为数字化时代研发体系不可或缺的一环,和企业建设…...

【Python】tqdm 模块
import mathfrom tqdm import tqdm, trange# 计算阶乘 results_1 []for i in range(6666):results_1.append(math.factorial(i))这是一个循环计算阶乘的程序,我们不知道程序运行的具体情况,如果能加上一个程序运行过程的进度条,那可就太有趣…...

论文阅读:Adversarial Cross-Modal Retrieval对抗式跨模式检索
Adversarial Cross-Modal Retrieval 对抗式跨模式检索 跨模态检索研究的核心是学习一个共同的子空间,不同模态的数据可以直接相互比较。本文提出了一种新的对抗性跨模态检索(ACMR)方法,它在对抗性学习的基础上寻求有效的共同子空间…...

计算机网络复习
什么是DHCP和DNS DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。通过主机名,最终得到该主机名对应的…...

unity动画--动画绑定,转换,用脚本触发
文章目录如何制作和添加动画大概过程示例图将多组图片转化为动画放在对象身上实现动画之间的切换使用脚本触发Parameters(Trigger)如何制作和添加动画 大概过程示例图 将多组图片转化为动画放在对象身上 首先,我们要为我们要对象添加animator 然后我们要设置对应的…...
车载汽车充气泵PCBA方案
汽车为什么会需要充气泵呢?其实是由于乘用车中没有供气源,所以就必需充气泵来给避震器供气。充气泵是为了保障汽车车胎对汽车的行驶安全所配备的,防止遇上紧急问题时没有解决方案,同时也可以检测轮胎胎压。现阶段的充气泵方案&…...
Android 连接 MySQL 数据库教程
在 Android 应用程序中连接 MySQL 数据库可以帮助开发人员实现更丰富的数据管理功能。本教程将介绍如何在 Android 应用程序中使用低版本的 MySQL Connector/J 驱动程序来连接 MySQL 数据库。 步骤一:下载 MySQL Connector/J 驱动程序 首先,我们需要下…...

tmall.item.update.schema.get( 天猫编辑商品规则获取 )
¥开放平台免费API必须用户授权 Schema方式编辑天猫商品时,编辑商品规则获取 公共参数 请求地址: HTTP地址 http://gw.api.taobao.com/router/rest 公共请求参数: 公共响应参数: 点击获取key和secret 请求示例 TaobaoClient client new DefaultTaobao…...
Leetcode 2379. 得到 K 个黑块的最少涂色次数
目录 一、题目内容和对应链接 1.题目对应链接 2.题目内容 二、我的想法 三、其他人的题解 一、题目内容和对应链接 1.题目对应链接 Leetcode 2379. 得到 K 个黑块的最少涂色次数 2.题目内容 给你一个长度为 n 下标从 0 开始的字符串 blocks ,blocks[i] 要…...
[深入理解SSD系列 闪存实战2.1.3] 固态硬盘闪存的物理学原理_NAND Flash 的读、写、擦工作原理
2.1.3.1 Flash 的物理学原理与发明历程 经典物理学认为 物体越过势垒,有一阈值能量;粒子能量小于此能量则不能越过,大于此能 量则可以越过。例如骑自行车过小坡,先用力骑,如果坡很低,不蹬自行车也能 靠惯性过去。如果坡很高,不蹬自行车,车到一半就停住,然后退回去。 …...

总结:Linux内核相关
一、介绍看eBPF和Cilium相关内容时,碰到Cilium是运行在第 3/4 层,不明白怎么做到的,思考原理的时候就想到了内容,本文记录下内核相关知识。https://www.oschina.net/p/cilium?hmsraladdin1e1二、Linux内核主要由哪几个部分组成Li…...

flutter工程创建过程中遇到一些问题。
安装环境版本:JDK7.-JDK 8 Andriod SDK 10 flutter 版本 3.0 1.当创建完后flutter工程后会遇到 run gradle task assemlble Debug 的问题,需要设置远程仓库,共需要修改三个地方build.gradle两处以及flutter 下面的D:\FVM\versions\3.0.0\pac…...

记录实现操作系统互斥锁的一次思考
今天实现操作系统互斥锁的时候遇到一个有趣的问题。 场景 有两个进程分别名为 taskA,taskB,采取时间片轮转的方式交替运行——也即维护了一个 ready_queue,根据时钟中断来 FIFO 地调度任务。它们的任务是无限循环调用 sys_print() 来打印自…...

计算机SCI期刊的分值是什么意思? - 易智编译EaseEditing
影响因子(Impact Factor,IF)是美国ISI(科学信息研究所)的JCR(期刊引证报告)中的一项数据。 即某期刊前两年发表的论文在统计当年的被引用总次数除以该期刊在前两年内发表的论文总数。这是一个国际上通行的期刊评价指标。 例如,某期刊2005年影…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

华为OD机试-最短木板长度-二分法(A卷,100分)
此题是一个最大化最小值的典型例题, 因为搜索范围是有界的,上界最大木板长度补充的全部木料长度,下界最小木板长度; 即left0,right10^6; 我们可以设置一个候选值x(mid),将木板的长度全部都补充到x,如果成功…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...

elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...
云原生周刊:k0s 成为 CNCF 沙箱项目
开源项目推荐 HAMi HAMi(原名 k8s‑vGPU‑scheduler)是一款 CNCF Sandbox 级别的开源 K8s 中间件,通过虚拟化 GPU/NPU 等异构设备并支持内存、计算核心时间片隔离及共享调度,为容器提供统一接口,实现细粒度资源配额…...
Python学习(8) ----- Python的类与对象
Python 中的类(Class)与对象(Object)是面向对象编程(OOP)的核心。我们可以通过“类是模板,对象是实例”来理解它们的关系。 🧱 一句话理解: 类就像“图纸”,对…...
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ is not explicitly defined.
这个警告表明您在使用Vue的esm-bundler构建版本时,未明确定义编译时特性标志。以下是详细解释和解决方案: 问题原因: 该标志是Vue 3.4引入的编译时特性标志,用于控制生产环境下SSR水合不匹配错误的详细报告1使用esm-bundler…...