JMM内存模型详解(一)
本文开始死磕JMM(Java内存模型)由于知识点较多,分来写
该文为JMM第一篇
技术往往是枯燥的,本文文字较多
1. JMM是什么?
其实JMM很好理解,我简单的解释一下,在Java多线程中我们经常会涉及到两个概念就是线程之间是如何通信和线程之间的同步,那什么是线程之间的通信呢,其实就是两个线程之间互相交换信息线程之间通信的方式共有两种:一种就是共享内存,和消息传递。在共享内存中的并发模型中线程是通过读取主内存的共享信息来进行隐性通信的。在消息传递通信中线程之间没有公共的状态,只能通过发送消息来进行显性通信。然而这只是线程通信,那么同步呢,同步就是在多线程的情况下有顺序的去执行。在共享内存中同步时显式进行的,在代码中我们必须要去指定方法需要同步执行比如说加同步锁等。在消息传递的并发模型中发送消息必须是在消接收之前,所以同步时隐式的。
2.为什么要涉及到线程并发通信
java内存模型其实可以说是Java并发内存模型,在Java中是采用的共享内存模型的方式,所以Java线程之间的通信是隐式进行的,对我们是完全透明的,如果你不了解通信机制的话会产生各种线程可见性的问题。其实在Java中所有的静态域,域和数组元素都存在堆内存中,堆内存在线程中是共享的一般我们都称之为共享变量,局部变量,方法定义参数和异常处理参数不会在线程中共享,所以不会存在线程可见性的问题。上面我就说过线程之间的通信是由JMM来进行控制的,JMM来决定了一个线程操作了共享变量后如何对另一个线程可见。从上面所说的概念来看的话,JMM定义了线程与主内存的关系。
3.JMM规定
其实这样做的原因就是Java是跨平台语言,在个操作系统中内存都有一定的差异性,这样久造成了并发不一致,所以JMM的作用就是用来屏蔽掉不同操作系统中的内存差异性来保持并发的一致性。同时JMM也规范了JVM如何与计算机内存进行交互。简单的来说JMM就是Java自己的一套协议来屏蔽掉各种硬件和操作系统的内存访问差异,实现平台一致性达到最终的"一次编写,到处运行",说了这么多,JMM到底是怎么控制的呢?然后如何通信的呢?我们继续往下看。
4.模型
JMM是一个抽象的概念,并不是真实的存在,它涵盖了缓冲区,寄存器以及其他硬件和编译器优化。
Java内存模型抽象图如下:

从上图可以看出每个线程都有一个本地内存,如果线程想要通信的话要执行一下步骤:
- A线程先把本地内存的值写入主内存
- B线程从主内存中去读取出A线程写的值
再看下面的这个图,表示了A如何向B发送消息

假设这时候有一个共享变量X默认值都是为0,那么线程A把X的值修改为1,这时候如何才能同步到B线程呢。
如果A线程把X修改成1之后,A线程会把X从A的本地内存中写入到主内存中,这样的话主内存的X就等于1了,这时候B线程就会去读取主内存的X变量,存入B的本地内存中,这样B线程的X变量值也就会变成了1。这样对吗。那现在如何通信我是知道了关键它究竟是如何来实现的,就是如何来实现通信的呢?
5.通信
上面所说的步骤其实就是实现了线程之间的通信,但是不要以为线程之间的通信就是这么简单的,其实在Java中JMM内存模型定义了八种操作来实现同步的细节。
- read 读取,作用于主内存把变量从主内存中读取到本本地内存。
- load 加载,主要作用本地内存,把从主内存中读取的变量加载到本地内存的变量副本中
- use 使用,主要作用本地内存,把工作内存中的一个变量值传递给执行引擎,每当虚拟机遇到一个需要使用变量的值的字节码指令时将会执行这个操作。、
- assign 赋值 作用于工作内存的变量,它把一个从执行引擎接收到的值赋值给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
- store 存储 作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作。
- write 写入 作用于主内存的变量,它把store操作从工作内存中一个变量的值传送到主内存的变量中。
- lock 锁定 :作用于主内存的变量,把一个变量标识为一条线程独占状态。
- unlock 解锁:作用于主内存变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。
所以看似简单的通信其实是这八种状态来实现的。
同时在Java内存模型中明确规定了要执行这些操作需要满足以下规则:
- 不允许read和load、store和write的操作单独出现。
- 不允许一个线程丢弃它的最近assign的操作,即变量在工作内存中改变了之后必须同步到主内存中。
- 不允许一个线程无原因地(没有发生过任何assign操作)把数据从工作内存同步回主内存中。
- 一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量。即就是对一个变量实施use和store操作之前,必须先执行过了assign和load操作。
- 一个变量在同一时刻只允许一条线程对其进行lock操作,lock和unlock必须成对出现
- 如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前需要重新执行load或assign操作初始化变量的值
- 如果一个变量事先没有被lock操作锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定的变量。
- 对一个变量执行unlock操作之前,必须先把此变量同步到主内存中(执行store和write操作)。
所以上面说的操作要严格执行。
目前写了这么多,下文预告:
LinkedHashMap源码分析
参考资料《深入Java内存模型》
JMM内存模型详解(一)的更多相关文章
- 云时代架构阅读笔记六——Java内存模型详解(二)
承接上文:云时代架构阅读笔记五——Java内存模型详解(一) 原子性.可见性.有序性 Java内存模型围绕着并发过程中如何处理原子性.可见性和有序性这三个特征来建立的,来逐个看一下: 1.原子性(At ...
- flink内存模型详解与案例
任务提交时的一些yarn设置(通用客户端模式) 指定并行度 -p 5 \ 指定yarn队列 -Dyarn.appl ...
- Java 内存模型详解
概述 Java的内存模型(Java Memory Model )简称JMM.首先应该明白,Java内存模型是一个规范,主要规定了以下两点: 规定了一个线程如何以及何时可以看到其他线程修改过后的共享变量 ...
- java内存模型详解
对于本篇文章,将从四个概念来介绍:内存模型基础,重排序,顺序一致性和happens-before 1.内存模型基础 在并发编程中,有两个关键问题:线程之间如何通信和如何同步.由此而引出了两种并发模型: ...
- 云时代架构阅读笔记五——Java内存模型详解(一)
什么是Java内存模型 Java虚拟机规范中试图定义一种Java内存模型(Java Memory Model,JMM)来屏蔽掉各种硬件和操作系统的访问差异,以实现让Java程序在各种平台下都能达到一致 ...
- Java虚拟机:内存模型详解
版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 我们都知道,当虚拟机执行Java代码的时候,首先要把字节码文件加载到内存,那么这些类的信息都存放在内存中的哪个区域呢?当我们创建一个对象实 ...
- 深度历险:Redis 内存模型详解
https://mp.weixin.qq.com/s/Gp6Ur7omGY6ZqDWygU2meQ Redis 是目前最火爆的内存数据库之一,通过在内存中读写数据,大大提高了读写速度,可以说 Redi ...
- JVM内存模型详解
内存模型 内存模型如下图所示 堆 堆是Java虚拟机所管理的内存最大一块.堆是所有线程共享的一块内存区域,在虚拟机启动时创建.此内存区域唯一的目的就是存放对象实例.所有的对象实例都在这里分配内存 Ja ...
- 02-java性能调优-JVM内存模型详解
JVM整体结构与内存模型之间的关系 JVM整体结构图如下: 先贴一个代码: package com.jvm.jvmCourse2; public class Math { public static ...
随机推荐
- 关于MarkDownPad2安装遇到的一些问题
关于MarkdownPad MarkdownPad是Windows下的一个多功能Markdown编辑器.即时看到你的Markdown文件,当你创建它们的时候,看起来就像是在HTML中的一样.当您输入时 ...
- javascript案例之放大镜效果
效果图 如何实现该效果呢?? 我们先来进行分析 实现思路 1.鼠标移入移出事件 1>移入:悬浮块和大图显示 2>移出:悬浮块和大图隐藏 2.鼠标移动(悬浮块随着鼠标移动) 1>获 ...
- UVA10763 交换学生 Foreign Exchange 题解
题目链接: https://www.luogu.org/problemnew/show/UVA10763 题目分析: 本题我首先想到的做法是把每一个数都map一下,然后互相判断,例如a,b两人准备交换 ...
- Scala数据结构
Scala数据结构 主要的集合特质 Scala同时支持可变集合和不可变集合,优先采用不可变集合.集合主要分为三大类:序列(List),集(set),映射(map).所有的集合都扩展自Iterable特 ...
- SQL server 2014使用导出数据为Excel
1.打开SQL server 2014,连接至数据库引擎 2.在要导出的数据库上右击,选择"任务->导出数据" 3.数据源选择"SQL Server Native ...
- window平台下 cmd 命令窗口的编码设置
在WINDOWS上打开控制台界面,发现默认的编码是GBK,这样有时候写完的代码运行的时候就会出码,基于此,查阅各方资料,终于得出两种方案. 一.临时解决方案(只针对本次会话有效) 1. 打开控制台,输 ...
- .net core开发从未如此简单,比abp更接地气
在谈起java一家独大的时候,dotnet人员总是一边嘲笑大量滥竽充数的java从业者,一边羡慕人家的生态.以前是只能羡慕,现在dotnet core开源了,我们都可以为dotnet core的开原生 ...
- js获取手机系统语言
只需 navigator.language 就可以获取手机系统语言,要做国际化的童鞋可以看看 如图:(第一次是简体,第二次切换English),zh-CN,en-US是语言代码 更多语言代码,请查看h ...
- Apache之——多虚拟主机多站点配置的两种实现方案
Apache中配置多主机多站点,可以通过两种方式实现: 将同一个域名的不同端口映射到不同的虚拟主机,不同端口映射到不同的站点: 将同一个端口映射成不同的域名,不同的域名映射到不同的站点. 我们只需要修 ...
- [译]Python中的异步IO:一个完整的演练
原文:Async IO in Python: A Complete Walkthrough 原文作者: Brad Solomon 原文发布时间:2019年1月16日 翻译:Tacey Wong 翻译时 ...