要解决的问题

在硬件环境下,基于高速缓存的存储交互很好的解决了处理器与内存的速度之间的矛盾,但同时也带给计算机系统带来了复杂的缓存一致性问题。简单点说,在多处理器系统中,每个处理器都有自己的高速缓存,他们共享主内存,当在某个时刻,多个处理器的运算任务都涉及同一块内存区域,很有可能各自缓存中的运算结果不一致,此时若要执行将高速缓存中的数据同步回主内存的操作,那么问题就来了:系统以哪个缓存的数据为准? 由此便出现了解决缓存一致性的协议、规范。“内存模型”一词即指在特定的操作协议下,对特定的内存和高速缓存进行读写访问的过程抽象,不同架构的物理机器可以拥有自己的内存模型。JVM 也实现了这样的一套规范模型。

并发编程模型的分类

在并发编程中,需要解决的两个关键问题分别是:线程之间如何通信(以何种机制来交换信息)以及线程之间如何同步(不同线程之间操作发生的相对顺序机制)。

线程之间的通信机制有两种:共享内存和消息传递。在共享内存的并发模型里,线程之间共享程序的的公共状态,线程之间通过读-写内存中的公共状态来隐式进行通信;在消息传递的并发模型里,线程之间没有公共状态,必须通过明确的发送消息来显示通信。

在共享内存的并发编程模型里,同步就显得至关重要,必须显示指定。Java 的并发采用的就是共享内存模型,不同的线程之间无法访问对方本地内存中的变量,线程间变量值的传递均需要通过主内存来完成。

Java 内存模型的抽象

在 Java 中,所有实例域、静态域和数组元素存储在堆(主内存主要对应了堆中对象实例数据部分)中,堆内存在线程之间共享,因此他们也叫共享变量。而局部变量、方法参数和异常处理器参数是属于线程私有的,不会被共享。每个线程还有自己的工作内存,其中保存了被该线程使用到的变量的主内存副本拷贝,线程对共享变量的所有操作(读取、赋值等)都必须在工作内存中进行,而不能直接读-写主内存中的共享变量。是不是和如上描述的硬件机制非常相似!实际上就是如此:主内存可以看出直接对应于物理硬件的内存,工作内存优先使用的是寄存器和高速缓存,因为程序运行时主要访问的是工作内存。

如上图所示,线程A和线程B通过共享变量实现了隐式通信,同时通过 JMM 控制实现多个线程之间的同步。解决了多核、多线程间数据的共享以及对内存操作的有序性的问题。

内存间交互操作细节

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

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

read(读取):作用于主内存的共享变量,把一个共享变量的值从主内存传输到线程的工作内存的读缓冲区中,以便随后的 load 操作使用

load(载入):作用于工作内存的共享变量,把 read 操作从主内存中读取到读缓冲区中的变量值放入工作内存的共享变量副本中

use(使用):作于于工作内存的共享变量副本,把工作内存中的共享变量副本的值传递给执行引擎

assign(赋值):作用于工作内存的共享变量副本,把一个从执行引擎接收到的值赋给工作内存中的共享变量副本

store(存储):作用于工作内存的共享变量副本,把工作内存中的共享变量副本的值通过写缓冲区传送到主内存中,以便随后的 write 操作使用

write(写入):作用于主内存的共享变量,把 store 操作存储到写缓冲区的值放入主内存的共享变量中

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

上述 8 种原子操作还必须满足如下规则:

不允许 read 和 load、store 和 write 操作之一单独出现,即不允许一个变量从主内存读取了但工作内存不接受,或者从工作内存发起了回写但主内存不接受的情况出现。

read、load 和 store、write 此两类操作必须按顺序执行,但并非必须连续执行,也即在 read 和 load、store 和 write 操作之间是可以插入其他指令的

不允许一个线程丢弃它最近的 assign 操作,即变量在工作内存中改变了之后必须把该变化同步回主内存

不允许一个线程无原因地(没有发生任何 assign 操作)把数据从线程的工作内存同步回主内存

一个新的变量只能在主内存中“诞生”,不允许在工作内存中直接使用一个未被初始化(load 或 assign)的变量,即对一个变量实施 use 或 store 操作前必须先执行过 assign 或 load 操作

一个变量在同一时刻只允许一个一条线程对其进行 lock 操作,但 lock 操作可以被同一条线程重复执行多次,多次 lock 执行后,只有执行相同次数的 unlock 操作,变量才会被解锁

如果对一个变量执行 lock 操作,那将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行 load 或 assign 操作初始化变量的值

如果一个变量事先没有被 lock 操作锁定,那就不允许对它执行 unlock 操作,也不允许 unlock 一个被其它线程锁定的变量

对一个变量执行 unlock 前必须先把此变量同步回主内存中(执行 store、write 操作)

深入理解 Java 内存模型(一)- 内存模型介绍的更多相关文章

  1. 《深入理解 java 虚拟机》学习 -- 内存分配

    <深入理解 java 虚拟机>学习 -- 内存分配 1. Minor GC 和 Full GC 区别 概念: 新生代 GC(Minor GC):指发生在新生代的垃圾收集动作,因为 Java ...

  2. 深入理解Java虚拟机(一)——JVM内存模型

    文章目录 程序计数器 定义 作用 特点 Java虚拟机栈 定义 特点 本地方法栈 定义 Java堆 定义 特点 方法区 定义 特点 运行常量池 直接内存 总结 Java虚拟机的内存空间分为五个部分: ...

  3. 【深入理解Java虚拟机】自动内存管理机制——垃圾回收机制

      Java与C++之间有一堵有内存动态分配和垃圾收集技术所围成的"高墙",墙外面的人想进去,墙里面的人却想出来.C/C++程序员既拥有每一个对象的所有权,同时也担负着每一个对象生 ...

  4. 【深入理解Java虚拟机】自动内存管理机制——内存区域划分

      Java与C++之间有一堵有内存动态分配和垃圾收集技术所围成的"高墙",墙外面的人想进去,墙里面的人却想出来.C/C++程序员既拥有每一个对象的所有权,同时也担负着每一个对象生 ...

  5. 深入理解Java虚拟机(自动内存管理机制)

    文章首发于公众号:BaronTalk 书籍真的是常读常新,古人说「书读百遍其义自见」还是很有道理的.周志明老师的这本<深入理解 Java 虚拟机>我细读了不下三遍,每一次阅读都有新的收获, ...

  6. 深入理解Java虚拟机之JVM内存布局篇

    内存布局**** ​ JVM内存布局规定了Java在运行过程中内存申请.分配.管理的策略,保证了JVM的稳定高效运行.不同的JVM对于内存的划分方式和管理机制存在部分差异.结合JVM虚拟机规范,一起来 ...

  7. 深入理解JAVA虚拟机原理之内存分配策略(二)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 1.对象优先在Eden分配 大多情况,对象在新生代Eden区分配.当Eden区没 ...

  8. 《深入理解Java内存模型》读书总结

    概要 文章是<深入理解Java内容模型>读书笔记,该书总共包括了3部分的知识. 第1部分,基本概念 包括"并发.同步.主内存.本地内存.重排序.内存屏障.happens befo ...

  9. 深入理解java内存模型系列文章

    转载关于java内存模型的系列文章,写的非常好. 深入理解java内存模型(一)--基础 深入理解java内存模型(二)--重排序 深入理解java内存模型(三)--顺序一致性 深入理解java内存模 ...

  10. 【Todo】【转载】深入理解Java内存模型

    提纲挈领地说一下Java内存模型: 什么是Java内存模型 Java内存模型定义了一种多线程访问Java内存的规范.Java内存模型要完整讲不是这里几句话能说清楚的,我简单总结一下Java内存模型的几 ...

随机推荐

  1. Android.mk 用法介绍

    一个Android.mk file用来向编译系统描述你的源代码.具体来说:该文件是GNU Makefile的一小部分,会被编译系统解析一次或多次.你可以在每一个Android.mk file中定义一个 ...

  2. 关于在Linux下apache-maven的安装

    本文所涉及到的软件如下:jdk版本号:1.7.0_45apache-maven版本号:3.1.1 apache-maven的安装过程如下: apache-maven的官方网址:http://maven ...

  3. 【CF725G】Messages on a Tree 树链剖分+线段树

    [CF725G]Messages on a Tree 题意:给你一棵n+1个节点的树,0号节点是树根,在编号为1到n的节点上各有一只跳蚤,0号节点是跳蚤国王.现在一些跳蚤要给跳蚤国王发信息.具体的信息 ...

  4. 安装pod

    1.ruby升级最新 sudo gem update -n /usr/local/bin --system 2. $ gem sources *** CURRENT SOURCES *** https ...

  5. Sql Server 统计当天数据

    方法一. ),日期字段名,)),) 方法二. Access: * FROM 表名 WHERE DAY(日期字段名)=DAY(NOW()) 查询当天之前一天的数据

  6. html如何绘制带尖角(三角)的矩形

    结合实际情况自己写的: .menu_triangle { height: 10px; width: 10px; background-color: #049888; transform: transl ...

  7. yii---对数组进行分页

    很多时候,我们会对多个数据进行分页处理,例如我最近开发的一个功能,系统消息,系统消息的来源是多个表,而且多个表之间的数据没有任何关联,这个时候,需要对多个表进行查询,查询返回的数据进行分页,而且采用的 ...

  8. Shell转义字符与变量替换

    转义字符 含义 \\ 反斜杠 \a 警报,响铃 \b 退格(删除键) \f 换页(FF),将当前位置移到下页开头 \n 换行 \r 回车 \t 水平制表符(tab键)  \v 垂直制表符 vim te ...

  9. [LintCode] Invert Binary Tree 翻转二叉树

    Given n points on a 2D plane, find the maximum number of points that lie on the same straight line. ...

  10. CSU 1804 - 有向无环图 - [(类似于)树形DP]

    题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1804 Bobo 有一个 n 个点,m 条边的有向无环图(即对于任意点 v,不存在从点 ...