Java虚拟机的内存模型
Posted tlz888
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java虚拟机的内存模型相关的知识,希望对你有一定的参考价值。
一、问题起源
这篇文章的起源其实是博主想要学习Java并发,计算机程序需要并发运行的原因在于:一方面cpu越来越多核化,另
一方面就是cpu和存储以及通信子系统的速度差距太大,粗略来说,cpu速度是ns级,内存100ns,硬盘ms,内存比cpu慢100倍,
硬盘比cpu慢100万倍,如果cpu需要等待这些速度慢的多的小伙伴,势必造成计算资源的浪费。
物理机为了解决cpu与内存的速度差,在两者之间加入了缓存,有缓存就会引入新问题,即缓存一致性问题。
图1(图片来自参考文献【1】)
为了解决缓存一致性问题,各个cpu在访问缓存和主内存时需要遵守一定的缓存一致性协议,
而把对特定的内存和缓存的访问过程抽象出来,就称之为“内存模型”。
二、JVM的内存模型
如下图所示,与物理机中cpu访问内存的结构类似,JVM内存模型中,所有变量都存储在主内存(Main Memory)
每条线程有自己的工作内存(Working Memory),变量在不同线程间的传递需要通过主内存。
图2(图片来自参考文献【1】)
如上所述,变量在线程间的传递需要工作内存和主内存间的交互。这种交互要遵循一定的一致性协议。
这里简单称为“交互协议”,交互协议具体体现为8中原子操作和一些操作规则,如下:
>8种原子操作
- lock:作用于主内存的变量,把一个变量标识为一条线程独占的状态;
- unlock:作用于主内存的变量,把一个变量从一条线程独占的状态释放出来,释放后的变量才可以被其他线程上锁;
- read:作用于主内存的变量,把一个变量从主内存传输到线程的工作内存,这一步仅仅是传输动作;
- load:作用于工作内存的变量,把read中传输过来的变量放入工作内存的副本中;
- use:作用于工作内存的变量,把工作内存中的一个变量传递给执行引擎,即线程在读取变量的值;
- assign:作用于工作内存的变量,把一个从执行引擎接收到的值赋给工作内存的变量,即线程在写变量的值;
- store:作用于工作内存的变量,把一个变量的值传输到主内存,这一步仅仅是传输动作;
- write:作用于主内存的变量,把store过来的变量值放入主内存的变量中。
>操作规则
- 不允许read和load,store和write操作之一单独出现;
- 不允许一个线程丢弃它的最近的assign操作,即变量在工作内存中改变了之后必须把该变量同步到主内存中;
- 不允许一个线程无原因地(没有发生过assign操作)把数据从线程的工作内存同步到主内存中;
- 一个新的变量只能在主内存中“诞生”,不允许在工作内存中直接使用一个未被初始化的变量,也就是说变量在use,store之前必须先执行了assign和load操作;
- 一个变量在同一个时刻只允许一条线程对其进行lock操作,但lock操作可以被同一条线程重复执行多次,而且,多次lock后,必须执行相同次数的unlock才能解锁变量;
- 如果对一个变量执行lock操作,那将会清空工作内存中此变量的值,在执行引擎使用变革变量前,需要重新执行load或assign操作初始化变量;
- 如果一个变量事先没有被lock操作锁定,那就不允许对它执行unlock操作,也不允许去unlock一个被其他线程锁定住的变量。
- 对一个变量执行unlock操作前,必须先把此变量同步回主内存中(执行store, write操作) 。
此外,volatile关键字比较特殊,需要单独说明:
volatile关键字具备两种语义特性:
一是保证变量对所有线程的“可见性”,即对于volatile变量,当一条线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的。
二是禁止指令重排序优化,
未完待添加。。。
并发环境下访问内存是否安全。
参考文献:
【1】深入理解Java虚拟机 by 周志明
【2】Java并发编程实战 机械工业出版社2012
以上是关于Java虚拟机的内存模型的主要内容,如果未能解决你的问题,请参考以下文章