5. Java内存模型JMM

文章目录

  • 计算机硬件存储体系
    • 基于计算机存储结构的 JMM
  • Java 内存模型 JavaMemoryModel
  • JMM规范下的三大特性
    • 原子性
    • 可见性
    • 有序性
  • 多线程对变量的读写过程
    • 读取过程
  • 多线程先行发生原则 happens-before
    • x,y 的 case 说明
    • happens-before 原则说明
    • happens-before 大原则
    • happens-before 的 8 条原则
      • 次序规则
      • 锁定规则
      • volatile 变量规则
      • 传递规则
      • 线程启动规则(Thread Start Rule)
      • 线程中断规则(Thread Interuption Rule)
      • 线程终止规则(Thread Termination Rule)
      • 对象终结规则(Finalizer)
    • Summary
    • case

大厂面试题

  • 什么是 Java 内存模型?
  • JMM 与 volatile 之间的关系?
  • JMM 有些特性(JMM 的三大特性是什么)
  • 为什么要有 JMM?(JMM 的能干什么?)(JMM 为什么出现?)
  • happens-before 先行发生原则是什么?

计算机硬件存储体系

  • 计算机存储结构,从本地磁盘到主存,再到 CPU 缓存,也就是硬盘到内存,到 CPU
  • 一般对应的程序的操作就是从数据库查数据到内存,然后 CPU 进行计算
  • CPU 中集成众多寄存器


基于计算机存储结构的 JMM

  • CPU 对内存的读写操作的数据不一致性问题
    • CPU 对数据的操作由外存->内存->三级缓存 3 个阶段,对内存读写操作存在数据不一致问题

  • question :
    • 如何解决因为硬件与操作系统数据读写速度不同导致的数据不一致问题?
  • answer :
    • JVM 定义了 JMM 用于屏蔽各种硬件与操作系统的内存访问差异,实现 JVM 跨平台达到一致的内存访问效果

Java 内存模型 JavaMemoryModel

JMM (Java 内存模型 JavaMomary Model,简称 JMM),

  • 本身是一种抽象的概念并不真实存在,仅仅描述了一组约定或规范,(本质)
  • 通过这组规范定义了程序中(特别是多线程)各个变量的读写访问方式,并决定了一个线程对共享变量的何时写入,以及如何变成对另一个线程可见(作用方式)
  • 关键技术点都是围绕多线程的原子性,可见性和有序性展开的(核心,原则)
  • 作用
    • 实现线程和主内存之间的抽象关系
    • 屏蔽底层硬件和操作系统的内存访问差异,实现 JVM 跨平台内存访问的一致性

JMM规范下的三大特性

原子性

  • 指的是一个操作不可被打断,多线程环境下,操作不能被其它线程所干扰

可见性

  • 当一个线程修改了某个共享变量的值,其他线程是否能够立即知道该变更
    • JMM 规范规定所有变量都存储在主内存中

  • 读写过程
    • 线程 A 先从主内存中读取到一个共享变量到自己的线程域内存中,作为本地共享变量的副本
    • 在本地线程域内存对本地共享变量进行修改
    • 将修改后的数据写回到主内存中
    • 线程 B 对线程 A 的更新进行读取
  • 设计思想
    • 系统主内存共享变量数据的修改被写入的时机是不确定的,多线程并发下可能存在"脏读"
    • 因此,每个线程都有自己的线程域,在线程域中保存共享变量副本
    • 线程对变量的所有操作都必须在本地线程域中进行
    • 不能直接读写主内存中的变量,不同线程之间也无法直接访问对方线程域中的变量
    • 线程间变量值的传递依赖主内存进行实现

  • 线程脏读现象

  • 可见性基于该现象,实现线程通知机制,当一个内存共享变量被修改时,其它线程获取修改通知
  • 其它方法
    • 使用基于悲观锁的加锁操作
    • 使用原子类变量

有序性

  • 对于一个线程执行的代码一般有悖于普通顺序从上到下执行,为了提升性能,编译器和处理器通常会对指令序列进行重排序
  • Java 规范规定 JVM 线程内部维持顺序化语义
    • 允许指令执行顺序与代码顺序的不一致性
    • 只需保证指令执行结果与代码顺序化执行结果一致即可
    • 该过程称为指令重排序
  • 优缺点
    • JVM 能根据处理器特征(CPU 多级缓存 Cache,多核处理器),适当对机器指令进行重排序,使机器指令能更符合 CPU 的执行特征,最大限度发挥机器性能
    • 指令重排可以保证串行语义一致,但不保证多线程间语义一致(可能产生脏读)
  • 重排序在代码执行流程中的位置

  • 串行单线程中代码顺序与重排序后指令执行结果一致
  • 处理器在进行重排序时必须要考虑指令之间的数据依赖
  • 多线程环境中线程交替执行,由于编译优化重排的存在,两个线程间使用的变量能发保持一致无法确定,结果存在随机性,某些情况下需要禁止指令重排序

多线程对变量的读写过程

读取过程

  • JVM 运行程序的实体是线程
    • 每个线程创建时 JVM 都会为其创建工作内存(又称为栈空间)
    • 工作内存是每个线程的私有数据区
  • Java 内存模型规定所有的变量均存储在主内存中
    • 主内存是共享内存区域,所有线程均可访问
  • 线程对于变量的操作须在工作内存中进行
    • 首先将主内存的变量复制到工作内存中,对变量完成操作后,将变量写回主内存
    • 不能直接操作主内存中的变量
    • 各线程的工作内存均保存主内存的变量的副本
    • 各线程间无法访问各种线程的工作内存,通过主线程传递变量

多线程先行发生原则 happens-before

在 JMM 中,如果一个操作执行的结果需要对另一个操作可见,或是代码重排序
则两个操作之间必须存在 happens-before(先行发生原则),逻辑上的先后关系

x,y 的 case 说明

x=5线程 A 执行
y=x线程 B 执行
上述称之为:写后续y 是否等于 5 呢?
  • 如果线程 A 的操作(x=5)happens-before 线程 B 的操作(y=x),那么可以确定线程 B 执行后 y=5 必定成立
  • 若不存在 heppens-before 原则,则 y=5 不一定成立
  • happens-before 对程序而言,包含了可见性和有序性的约束

happens-before 原则说明

Java 规范下 JMM 的 happens-before 原则,是判断数据是否存在竞争,线程是否安全的非常重要的手段
依赖此原则,代码编写过程就无需时时处处添加 volatile 和 synchronized 保证程序的有序性;仅通过 happens-before 原则下的规则就可以解决并发环境下两个操作之间是否可能存在冲突的所有问题,无需陷入晦涩难懂的底层编译原理中

happens-before 大原则

  • 一个操作 happens-before 另一个操作,第一个操作的执行结果对第二个操作可见
    • 第一个操作的执行顺序在第二个操作之前
  • 两个操作之间存在 happens-before 关系,并不意味着一定要按照 happens-before 原则制定的顺序来执行
    • 若重排序后的执行结果与 happens-before 一致,则重排序合法

happens-before 的 8 条原则

次序规则

  • 一个线程内,按照代码顺序,写在前面的操作,先行发生于写在后面的操作
  • 线程内部,串行,顺序结构

锁定规则

  • 一个 unLock 操作 happens-before 后面(时间上的先后)对同一个锁的 lock 操作
  • 同一把锁,若存在一次 lock 则需要先释放,才能再加锁(除非可重入锁)

volatile 变量规则

  • 对于一个 volatil 变量的写操作先行发生于后面对该变量的读操作,则前面的写对后面的读是可见的
  • 先写后读,写的操作,对读操作可见

传递规则

  • 若 A 先行发生于 B,B 先行 发生于 C,则 A 先行发生于 C

线程启动规则(Thread Start Rule)

  • Thread 对象的 start()方法优先发生于线程的每一个动作
  • Thread 线程的所有操作都基于是否成功执行了 start()

线程中断规则(Thread Interuption Rule)

  • 对线程 interupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生
    • 先调用 interupt()(仅将标志位设置为 true),后面 cpu 看心情中断线程
  • 通过 Thread.interupted()检测到是否发生中断

线程终止规则(Thread Termination Rule)

  • 线程中的所有操作先行发生于对此线程的终止检测
  • 通过 isAlive 等方式检测线程是否已经终止执行

对象终结规则(Finalizer)

  • 一个对象的初始化完成(构造方法执行结束),先行发生于它的 finalize()方法的开始
    • finalize()方法,通常目的是对象不可撤回的丢弃之前执行的清理操作
  • 对象没有完成初始化之前,不能调用 finalize 方法

Summary

  • 在 Java 中 Happens-Before 的语义本质上就是一种可见性
  • A Happens-Before B 意味着 A 的方式过的事情对 B 而言是可见的,无论 A 与 B 两个事件是否在同一个线程中
  • JMM 对 Happens-Before 的设计
    • 针对程序员,设计了 happens-before8 条规则
    • 针对 JVM,为了尽可能少的对编译器和处理器约束而提高性能,JMM
      • 在不影响程序执行结果的前提下对其不做要求(允许指令重排序)

case

image.png

假设存在线程 A 和 B
线程 A 调用 setValue()
线程 B 调用同一个对象 getValue()
则线程 B 的到的返回值是什么?

  • analysis
  • 两个方法不在同一个线程中,不满足次序规则(单线程)
  • 两个方法没有加锁,不满足锁定规则
  • 变量没通过 volatile 修饰,不满足 volatile 变量规则
  • 不满足传递规则
  • 不涉及线程生命周期和对象终结规则
  • anwser

由于不满足 happens-before 原则,
虽然可以确定 A 线程优先于 B 线程执行,但是无法确认 B 线程最终得到的结果
该代码是线程不安全的

  • 修复方案 1
    • 加锁,将 get 和 set 方法加上悲观锁
    • 弊端,写读均为独占锁,读操作使得代码效率下降,适合并发量小的场景
  • 修复方案 2
    • 将 value 定义为 volatile 变量
    • 由于 setter 方法对 value 的修改不依赖于 value 原值,满足 volatile 关键字使用场景

image.png


在这里插入图片描述

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

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

相关文章

如何转行成为产品经理?

转行NPDP也是很合适的一条发展路径,之后从事新产品开发相关工作~ 一、什么是NPDP? NPDP 是产品经理国际资格认证,美国产品开发与管理协会(PDMA)发起的,是目前国际公认的唯一的新产品开发专业认证&#xff…

fasta文件与fastq文件相互转化Python脚本

fa文件与fq文件互相转换 今天分享的内容是fasta文件与fastq文件的基本知识,以及通过Python实现两者互相转换的方法。 测序数据公司给的格式通常是fq.gz,也就是fastq文件,计算机的角度来说,生物的序列属于一种字符串,就…

CVHub | 万字长文带你全面解读视觉大模型(建议收藏!)

本文来源公众号“CVHub”,仅用于学术分享,侵权删,干货满满。 原文链接:万字长文带你全面解读视觉大模型 0 导读 众所周知,视觉系统对于理解和推理视觉场景的组成特性至关重要。这个领域的挑战在于对象之间的复杂关系…

形参化类 ‘Result‘ 的原始使用

在编程中,特别是在面向对象编程(OOP)中,当我们说“形参化类”或“参数化类”,我们实际上是指泛型(Generics)的概念。泛型允许在定义类、接口和方法时使用类型参数。这样,你可以创建可…

99.qt qml-单例程序实现

在之前讲过: 58.qt quick-qml系统托盘实现https://nuoqian.blog.csdn.net/article/details/121855993 由于,该示例只是简单讲解了系统托盘实现,并没有实现单例程序,所以多次打开后就会出现多个exe出现的可能,本章出一章QML单例程序实现, 多次打开始终只显示出第一个打开…

DiT:Scalable Diffusion Models with Transformers

TOC 1 前言2 方法和代码 1 前言 该论文发表之前,市面上几乎都是用卷积网络作为实际意义上的(de-facto)backbone。于是一个想法就来了:为啥不用transformer作为backbone呢? 文章说本论文的意义就在于揭示模型选择对于…

用python写一个自动进程守护,带UI

功能是指定程序关闭后自动重启,并点击1作为启动 原来的想法是群成员说的某软件打包后,软件进程被杀后,界面白屏。所以写了个计算器重启demo进行进程守护 import subprocess import time import pyautogui import psutil #用计算器做演示。 d…

WiFi模块助力敏捷办公:现代办公室的关键角色

随着信息技术的飞速发展,现代办公室正经历着一场数字化和智能化的变革。在这一变革过程中,WiFi模块作为无线通信技术的核心组成部分,扮演着关键的角色,为敏捷办公提供了强大的支持。本文将深入探讨WiFi模块在现代办公室中的关键角…

Spring Boot工作原理

Spring Boot Spring Boot 基于 Spring 开发,Spirng Boot 本身并不提供 Spring 框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于 Spring 框架的应用程序。也就是说,它并不是用来替代 Spring 的解决方案,而是和 Spr…

安康杯安全知识竞赛上的讲话稿

各位领导、同志们: 经过近半个月时间的准备,南五十家子镇平泉首届安康杯安全生产知识竞赛初赛在今天圆满落下帏幕,经过紧张激烈的角逐, 代表队、 代表队和 代表队分别获得本次竞赛的第一、二、三名让我们以热烈的掌声表示祝…

使用插件vue-seamless-scroll 完成内容持续动态

1、安装插件 npm install vue-seamless-scroll --save 2、项目中引入 //单独引入import vueSeamlessScroll from vue-seamless-scrollexport default {components: { vueSeamlessScroll},}//或者在main.js引入import scroll from vue-seamless-scrollVue.use(scroll)3、页面使…

SRS服务器ffmpeg 推流rtmp超时中断

ffmpeg错误显示 failed to update header with correct duration failed to update header with correct filesize. Error writing trailer of rtmp://----- broken pipe SRS日志错误显示 serve error code2056 kickoffforidle : service cycle : rtmp stream service: timeou…

基于Pytorch搭建分布式训练环境

Pytorch系列 文章目录 Pytorch系列前言一、DDP是什么二、DPP原理terms、nodes 和 ranks等相关术语解读DDP 的局限性为什么要选择 DDP 而不是 DP代码演示1. 在一个单 GPU 的 Node 上进行训练(baseline)2. 在一个多 GPU 的 Node 上进行训练临门一脚&#x…

【深度学习笔记】稠密连接网络(DenseNet)

注:本文为《动手学深度学习》开源内容,部分标注了个人理解,仅为个人学习记录,无抄袭搬运意图 5.12 稠密连接网络(DenseNet) ResNet中的跨层连接设计引申出了数个后续工作。本节我们介绍其中的一个&#xf…

5个实用的PyCharm插件

大家好,本文向大家推荐五个顶级插件,帮助开发人员提升PyCharm工作流程,将生产力飞升到新高度。 1.CodiumAI 安装链接:https://plugins.jetbrains.com/plugin/21206-codiumate--code-test-and-review-with-confidence--by-codium…

Windows上基于名称快速定位文件和文件夹的免费工具Everything

在Windows上搜索文件时,使用windows上内置搜索会很慢,这里推荐使用Everything工具进行搜索。 "Everything"是Windows上一款搜索引擎,它能够基于文件名快速定位文件和文件夹位置。不像Windows内置搜索,"Everything&…

容器:Docker部署

docker 是容器,可以将项目的环境(比如 java、nginx)和项目的代码一起打包成镜像,所有同学都能下载镜像,更容易分发和移植。 再启动项目时,不需要敲一大堆命令,而是直接下载镜像、启动镜像就可以…

echarts x轴名称过长tip显示全称

xAxis的axisLabel的内容如下: axisLabel: { rotate: -45, color: document.body.className.indexOf(custom-f4c46d) > -1 ? #fff : #343434, // 显示省略号操作(第一步) formatter: function (value) { var val if (value.length >…

NTP协议介绍

知识改变命运,技术就是要分享,有问题随时联系,免费答疑,欢迎联系! 网络时间协议NTP(Network Time Protocol)是TCP/IP协议族里面的一个应用层协议,用来使客户端和服务器之间进行时…

C while 循环

只要给定的条件为真,C 语言中的 while 循环语句会重复执行一个目标语句。 语法 C 语言中 while 循环的语法: while(condition) {statement(s); }在这里,statement(s) 可以是一个单独的语句,也可以是几个语句组成的代码块。 co…