Java内存模型

主内存与工作内存

Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。此处的变量包括实例变量、静态字段和构成数组对象的元素,但不包括局部变量与方法参数,因为局部变量与方法参数是线程私有的,不会被共享,不会存在竞争问题。

Java内存模型规定了所有变量都存储在主内存中。每条线程还有自己的工作内存,线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。不同线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成,线程、主内存、工作内存三者之间的关系如下图:
在这里插入图片描述

内存间交互操作

主内存与工作内存之间具体的交互协议,即一个变量如何从主内存拷贝到工作内存、如何从工作内存同步回主内存之类的实现细节,Java内存模型中定义了8种操作来完成,虚拟机实现时必须保证每一种操作都是原子的、不可再分的。8种操作如下:

  • lock(锁定)
    作用于主内存的变量,把一个变量标识为一条线程独占状态。

  • unlock(解锁)
    作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。

  • read(读取)
    作用于主内存的变量,把一个变量的值从主内存传输到线程的工作内存,以便随后的load操作使用。

  • load(载入)
    作用于工作内存的变量,把read操作从主内存中得到的变量值放入工作内存的变量副本中。

  • use(使用)
    作用于工作内存的变量,把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作。

  • assign(赋值)
    作用于工作内存的变量,把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。

  • store(存储)
    作用于工作内存的变量,把工作内存中一个变量的值传递到主内存中,以便随后的write操作使用。

  • write(写入)

    作用于主内存的变量,把store操作从工作内存中得到的变量值放入主内存的变量中。

Java内存模型规定在执行上面的8种基本操作时必须满足下面的规则:

  • 不允许read和load、store和write操作之一单独出现,即不允许一个变量从主内存读取了但工作内存不接受,或者从工作内存发起了回写但主内存不接受的情况出现。
  • 不允许一个线程丢弃它的最近的assign操作,即变量在工作内存中改变了之后必须把改变化同步会主内存。
  • 不允许一个线程无原因地把数据从线程的工作内存同步回主内存中。
  • 一个新的变量只能只能在主内存中“诞生”,不允许在工作内存中直接使用一个未被初始化的变量,也就是对一个变量实施use、store操作之前,必须要先执行过了assign和load操作。
  • 一个变量在同一个时刻只允许一条线程对其进行lock操作,但lock操作可以被同一条线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。
  • 如果对一个变量执行lock操作,那将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或者assign操作初始化变量的值。
  • 如果一个变量事先没有被lock操作锁定,那就不允许对它执行unlock操作,也不允许去unlock一个被其他线程锁定的变量。
  • 对一个变量执行unlock操作之前,必须先把此变量同步回主内存中。

volatile型变量的特殊规则

当一个变量定义为volatile之后,这个变量具备两种特性。

第一个是保证此变量对所有线程的可见性。这里的“可见性”是指当一条线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的。普通变量的值在线程间传递均需要通过主内存来完成,所以普通变量不能做到这一点。但这并不能保证Java操作的原子性,所以在不符合以下两条规则的运算场景中,仍然需要通过加锁来保证原子性。

  1. 运算结果并不依赖变量的当前值,或者能够确保只有单一的线程修改变量的值。
  2. 变量不需要与其他的状态变量共同参与不变约束。

第二个是禁止指令重排序优化,普通变量仅仅会保证在该方法执行的过程中所有依赖赋值结果的地方都能获取到正确的结果,而不能保证变量赋值操作的顺序与程序代码中的执行顺序一致。

原子性、可见性与有序性

原子性由Java内存模型来直接保证,能够保证原子性的操作有read、load、assign、use、store和write。如果应用场景需要一个更大范围的原子性保证,可以使用lock和unlock操作来满足这种需求。

可见性是指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。Java内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值这种依赖主内存作为传递媒介的方式来实现可见性的。

有序性,如果在本线程内观察,所有的操作都是有序的,即线程内表现为串行;如果在一个线程中观察另一个线程,所有的操作都是无序的,即指令重排序现象和工作内存与主内存同步延迟现象。

先行发生原则

先行发生是Java内存模型中定义的两项操作之间的偏序关系,如果说操作A先行发生与操作B,其实就是说在发生操作B之前,操作A产生的影响能被操作B观察到,“影响”包括修改了内存中共享变量的值、发送了消息、调用了方法等。在Java内存模型中有一些“天然的”先行发生关系,这些先行发生关系无需任何同步器协助就已经存在,可以在编码中直接使用。这些关系如下:

  • 程序次序规则

    在一个线程内,按照程序代码顺序,书写在前面的操作先行发生于书写在后面的操作。准确的说,应该是控制流顺序而不是程序代码顺序,因为要考虑分支、循环等结构。

  • 管程锁定规则

    一个unlock操作先行发生于后面对同一个锁的lock操作。这里必须是同一个锁。

  • volatile变量规则

    对一个volatile变量的写操作先行发生于后面对这个变量的读操作,后面指的是时间上的先后顺序。

  • 线程启动规则

    Thread对象的start()方法先行发生于此线程的每一个动作。

  • 线程终止规则

    线程中的所有操作都先行发生于对此线程的终止检测,可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。

  • 线程中断规则

    对线程interrupt()方法调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测到是否有中断发生。

  • 对象终结规则

    一个对象的初始化完成先行发生于它的finalize()方法的开始。

  • 传递性

    如果操作A先行发生于操作B,操作B先行发生于操作C,那就可以得出操作A先行发生于操作C的结论。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GreptimeAI + Xinference 联合方案:高效部署并监控你的 LLM 应用

随着人工智能技术的迅速进步,OpenAI 已经崭露头角,成为该领域的领军者之一。它在多种语言处理任务上表现卓越,包括机器翻译、文本分类和文本生成等方面。随着 OpenAI 的兴起,同时涌现的还有许多其他优质的开源大语言模型&#xff…

函数递归(Recursion)一篇便懂

递归的概念 在 C 语言中,递归(Recursion)是一种函数调用自身的编程技术。当一个函数在其定义中调用自身时,就称为递归函数。 了解递归思想 把⼀个大型复杂问题层层转化为⼀个与原问题相似,但规模较小的子问题来求解…

OpenAI Altman曝光GPT-5后,你对未来大模型有什么期待?

最近OpenAI首席执行官 Sam Altman 在达沃斯论坛接受媒体采访时表示,他现在的首要任务就是推出下一代大模型,这款模型可能被称为GPT-5,与现有模型相比,GPT-5 “能做更多、更多的事情”。 Altman认为GPT-5仍处于早期阶段&#xff0…

运维神器Ansible的常用模块

引言:话不多说,今天分享一下Ansible的常用模块,建议收藏哦 1、ping模块 ping模块可以进行主机连通性测试 命令格式 ansible 主机或主机组 -m ping 例,成功显示如下: 2、command 模块 command模块可以直接在远程主机…

java并发面试题

目录 一.线程基础 1.线程和进程的区别 2.并行和并发的区别 3.创建线程的方式 4.线程包括哪些状态,状态之间如何变化 5.如何保证线程间按顺序执行 6.notify()和notifyAll()的区别 7.java中wait和sleep方法的区别 8.如何停止正在运行的线程 二.线程安全 1.synchronized…

springboot121编程训练系统设计与实现

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的编程训练系统设计与实现 适用于计算机类毕业设计,课程设计参考与学习用途。仅供学习参考, 不得用于商业或者非法用途,否则,一切后果请用户自负。 看运行截图看 第五章 第四…

liunx服务异常分析

systemd-journald 服务分析系统日志 实验环境:本地 Centos 7 请勿在 vps 服务器上操作!!! 1 systemd-journald 介绍 systemd-journald 是一个收集并存储各类日志数据的系统服务。 它创建并维护一个带有索引的、 结构化的日志数据…

浅谈WPF之UI布局

一个成功的软件,离不开人性化的UI设计,如何抓住用户第一视觉,让用户产生依赖感,合适优雅的布局必不可少。本文以一些简单的小例子,简述WPF中布局 面板 控件的使用,仅供学习分享使用,如有不足之处…

学习笔记-李沐动手学深度学习(二)(08-09、线性回归、优化算法、Softmax回归、损失函数、图片分类)

总结 以_结尾的方法,好像是原位替换(即 原地修改,就地修改变量)如 fill_() 感恩的心:(沐神的直播环境) 08-线性回归基础优化算法 引言(如何在美国买房) 根据现在行…

51单片机ESP8266

一、MQTT透传AT固件 安信可提供的烧录WiFi固件工具: 链接: https://docs.ai-thinker.com/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B72 安信可提供的固件库链接: https://docs.ai-thinker.com/%E5%9B%BA%E4%BB%B6%E6%B1%87%E6%80%BB 经过测试,选择这个不可以…

LeetCode刷题---删除排序链表中的重复元素 II

解题思路: 1.首先定义虚拟节点dummy,dummy的下一个节点指向head节点。 2.定义辅助节点cur指向dummy节点 3.开始遍历链表,如果当前节点cur的下一个节点和下下一个节点都不为空的情况下,对cur的下一个节点和下下一个节点的值进行判断。 4.如果当前节点cur的…

Python基础第九篇(Python可视化的开发)

文章目录 一、json数据格式(1).转换案例代码(2).读出结果 二、pyecharts模块介绍三、pyecharts模块入门(1).pyecharts模块安装(2).pyecharts模块操作(1).代码…

洛谷刷题-【入门2】分支结构

目录 1.苹果和虫子 题目描述 输入格式 输出格式 输入输出样例 2.数的性质 题目描述 输入格式 输出格式 输入输出样例 3.闰年判断 题目描述 输入格式 输出格式 输入输出样例 4.apples 题目描述 输入格式 输出格式 输入输出样例 5.洛谷团队系统 题目描述 …

什么是信号抖动

对于抖动,有一个简单而直观的定义: “Jitter is defined as the short-term variations of a digital signal’s significant instants from their ideal positions in time.” 翻译过来,就是: “抖动被定义为一个数字信号的重要时…

Duplicate keys detected: ‘41172‘. This may cause an update error.

在写项目的过程中,遇到了 Duplicate keys detected: 41172. This may cause an update error. 这个错误具体错误信息如下: 原因:v-for 循环时,用了重复的key值 解决方案: 1、单个v-for循环,选择id或其他唯一…

【C++杂货铺】快速学会命名空间

目录 🌈前言 📁 命名空间的定义 📁 命名空间的使用 ● 加命名空间名称及作用域限定符 ● 使用using将命名空间中某个成员引入 ● 使用using namespace 命名空间名称 引入 📁 C输入 和 输出 📁 总结 &#x1f3…

微信小程序首页、界面布局、功能简洁(示例三)

微信小程序首页界面布局、页面简洁,功能简单 直接上具体代码: 1、js代码 Page({/*** 页面的初始数据*/data: {imgList: [../../images/demo.jpg, ../../images/demo.jpg, ../../images/demo.jpg],navList: [{src: ../../images/nav1.png,title: 菜单一}…

《统计学习方法:李航》笔记 从原理到实现(基于python)-- 第 2章感知机

文章目录 第 2章感知机2.1 感知机模型2.2 感知机学习策略2.2.1 数据集的线性可分性2.2.2 感知机学习策略 2.3 感知机学习算法2.3.1 感知机学习算法的原始形式2.3.2 算法的收敛性2.3.3 感知机学习算法的对偶形式 实践:二分类模型(iris数据集)数…

【机器学习300问】17、什么是欠拟合和过拟合?怎么解决欠拟合与过拟合?

一个问题出现了,我们首先要描述这个问题,然后分析问题出现的原因,找到原因后提出解决方案。废话不多说,直接上定义,然后通过回归和分类任务的例子来做解释。 一、什么是欠拟合和过拟合? (1&am…

微信小程序之全局配置-window和tabBar

学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您: 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持,想组团高效学习… 想写博客但无从下手,急需…