当前位置: 首页 > news >正文

Java虚拟机之内存模型

.java并发基础

 在并发编程中存在两个关键问题①线程之间如何通信 ②线程之间如何同步。

通信

通信是指线程之间以何种机制来交换信息。在命令式编程中,线程之间的通信机制有两种:共享内存和消息传递。

在共享内存的并发模型里,线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信。

在消息传递的并发模型里,线程之间没有公共状态,线程之间必须通过明确的发送消息来显式进行通信。

同步

同步是指程序用于控制不同线程之间操作发生相对顺序的机制。

在共享内存并发模型里,同步是显式进行的。程序员必须显式指定某个方法或某段代码需要在线程之间互斥访问。

在消息传递的并发模型里,由于消息的发送必须在消息的接收之前, 因此同步是隐式进行的。

Java并发采用的是共享内存模型,通信隐式进行;同步显示指定。

二.内存模型

       Java内存模型JMM(Java Memory Model)主要目标是定义程序中各个变量(非线程私有)的访问规则,即在虚拟机中将变量存储到内存和从内存取出变量这样的底层细节。Java中每个线程都有自己私有的工作内存。工作内存保存了被该线程使用的变量的主内存副本拷贝,线程对变量的读写操作都必须在工作内存进行,无法直接读写主内存中的变量。两个线程无法直接访问对方的工作内存。

  • 每一个线程有一个工作内存和主存独立
  • 工作内存存放主存中变量的值的拷贝

(1)当数据从主内存复制到工作存储时,必须出现两个动作:第一,由主内存执行的读(read)操作;第二,由工作内存执行的相应的load操作;当数据从工作内存拷贝到主内存时,也出现两个操作:第一个,由工作内存执行的存储(store)操作;第二,由主内存执行的相应的写(write)操作。
(2) 每一个操作都是原子的,即执行期间不会被中断。
(3)对于普通变量,一个线程中更新的值,不能马上反应在其他变量中,如果需要在其他线程中立即可见,需要使用 volatile 关键字

内存模型的抽象:

        在 Java 中,所有实例域、静态域 和数组元素存储在堆内存中,堆内存在线程之间共享。局部变量、方法定义参数 和 异常处理器参数 不会在线程之间共享,它们不会有内存可见性问题,也不受内存模型的影响。Java 线程之间的通信由 Java 内存模型(JMM)控制。JMM 决定了一个线程对共享变量的写入何时对另一个线程可见。从抽象的角度来看,JMM 定义了线程与主内存之间的抽象关系:线程之间的共享变量存储在主内存中,每一个线程都有一个自己私有的本地内存,本地内存中存储了该变量以读/写共享变量的副本。本地内存是 JMM 的一个抽象概念,并不真实存在。

JMM抽象示意图如下:

从上图来看,如果线程 A 和线程 B 要通信的话,要如下两个步骤:

1、线程 A 需要将本地内存 A 中的共享变量副本刷新到主内存去

2、线程 B 去主内存读取线程 A 之前已更新过的共享变量

步骤示意图:

举个例子:

本地内存 A 和 B 有主内存共享变量 X 的副本。假设一开始时,这三个内存中 X 的值都是 0。线程 A 正执行时,把更新后的 X 值(假设为 1)临时存放在自己的本地内存 A 中。当线程 A 和 B 需要通信时,线程 A 首先会把自己本地内存 A 中修改后的 X 值刷新到主内存去,此时主内存中的 X 值变为了 1。随后,线程 B 到主内存中读取线程 A 更新后的共享变量 X 的值,此时线程 B 的本地内存的 X 值也变成了 1。

       整体来看,这两个步骤实质上是线程 A 再向线程 B 发送消息,而这个通信过程必须经过主内存。JMM 通过控制主内存与每个线程的本地内存之间的交互,来为 Java 程序员提供内存可见性保证。

内存间通信的指令:

 

 

 

 

 



转载于:https://www.cnblogs.com/Dream-chasingGirl/p/10345426.html

相关文章:

  • [CTSC2014]企鹅QQ
  • 单词接龙---牛客网
  • Bzoj2164 采矿(线段树+树链剖分)
  • 个位数统计
  • CF528D Fuzzy Search (生成函数+FFT)
  • c++随机数引擎
  • 《学习之道》第六章番茄工作法
  • 加密_滴答~滴
  • Ext中 grid 设置行样式
  • 技术研究 | 我所了解的物联网设备渗透手段(硬件篇)
  • Exif xss
  • C语言复习1_变量与数据类型
  • linux操作文本三个命令awk、grep、sed
  • 【c#】RabbitMQ学习文档(三)Publish/Subscribe(发布/订阅)
  • 食用指南
  • 「前端」从UglifyJSPlugin强制开启css压缩探究webpack插件运行机制
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • AHK 中 = 和 == 等比较运算符的用法
  • eclipse(luna)创建web工程
  • Python实现BT种子转化为磁力链接【实战】
  • Spring Security中异常上抛机制及对于转型处理的一些感悟
  • TypeScript迭代器
  • Vue官网教程学习过程中值得记录的一些事情
  • weex踩坑之旅第一弹 ~ 搭建具有入口文件的weex脚手架
  • 闭包,sync使用细节
  • 对超线程几个不同角度的解释
  • 来,膜拜下android roadmap,强大的执行力
  • 前端
  • 听说你叫Java(二)–Servlet请求
  • 一份游戏开发学习路线
  • 因为阿里,他们成了“杭漂”
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • ​DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座
  • # Apache SeaTunnel 究竟是什么?
  • (2)STM32单片机上位机
  • (6)添加vue-cookie
  • (C#)一个最简单的链表类
  • (poj1.2.1)1970(筛选法模拟)
  • (附源码)ssm跨平台教学系统 毕业设计 280843
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (原+转)Ubuntu16.04软件中心闪退及wifi消失
  • (自用)learnOpenGL学习总结-高级OpenGL-抗锯齿
  • .NET Core 将实体类转换为 SQL(ORM 映射)
  • .NET/C# 使用反射调用含 ref 或 out 参数的方法
  • .sh
  • :O)修改linux硬件时间
  • @selector(..)警告提示
  • @vue/cli脚手架
  • [ Linux 长征路第五篇 ] make/Makefile Linux项目自动化创建工具
  • [ 蓝桥杯Web真题 ]-Markdown 文档解析
  • [Android] Upload package to device fails #2720
  • [BZOJ1877][SDOI2009]晨跑[最大流+费用流]
  • [C/C++] C/C++中数字与字符串之间的转换
  • [Docker]五.Docker中Dockerfile详解
  • [hdu 4552] 怪盗基德的挑战书