Java 线程 — JMM Java内存模型
JMM
Java Memory Model,Java内存模型,属于语言级的内存模型
并发编程中存在的问题:
- 如何通信:用于线程之间交换信息。两种方式:共享内存,消息传递
- 如何同步:用于控制不同线程间操作发生的相对顺序。共享内存的同步是显式的,消息传递的同步是隐式的,因为消息发送必须在消息接受之前,已经隐式包含了这个顺序关系
Java并发采用的是共享内存模型,内存模型的抽象结构如下图:
线程A和线程B通信的两个步骤:
- 线程A把本地内存中更新过的共享变量刷新到主内存中去
- 线程B去主内存中读取线程A之前更新过的共享变量
JMM通过控制主内存和线程的本地内存之间的交互,来为程序提供内存可见性的保证
重排序
在执行程序时,为了提高性能,编译器和处理器会对指令做重排序,包括以下三类:
- 编译器在不改变单线程语意的前提下对语句执行顺序的优化
- 处理器对不存在数据依赖性的语句,改变语句对应指令的执行顺序
- 内存系统的重排序
也就是说从Java源码到实际执行的指令序列经历了:
源代码——>编译器优化——>处理器优化——>内存系统重排序——>实际执行的指令序列
上述重排序都可能导致内存可见性问题
JMM属于语言级内存模型,在不同的编译器(软件)和不同的处理器平台(硬件)之上,通过以下方法保证一致的内存可见性:
- JMM的重排序规则禁止特定编译器的编译成排序
- JMM的处理器重排序规则会要求编译器在生成指令序列时,插入特定的内存屏障(Memory Barriers)指令
以上JMM的各种禁止重排序的规则和实现确保了happens-before
happens-before
基本原则
在保证执行结果正确的前提下尽可能提高执行的并行度
定义
- 如果A操作happens-before B,那么操作A的结果一定对操作B可见,而且操作A的执行顺序一定排在操作B前面(面向程序员:向程序员保证内存可见性)
- 两个操作存在happens-before关系,并不意味着Java平台的具体实现必须按照happens-before关系指定的顺序执行,只要保证执行结果正确JMM允许重排序(面向编译器和处理器:保证结果正确的前提下尽可能的优化并发性能)
规则
- 程序顺序规则:一个线程中每一个操作,happens-before于该线程所有后续操作
- 监视器锁规则:对于一个锁的解锁,happnes-before于对同一个锁的加锁
- volatile规则:对于volatile域的写,happens-before于任意后续对这个域的读
- 传递性规则:如果A happens-before于B,B happens-before于C,那么A happens-before于C
- start()规则:如果线程A执行ThreadB.start()操作,那么线程ThreadB.start()操作happens-before于ThreadB的任何操作
- join()规则:如果线程A执行ThreadB.join()操作并成功返回,那么ThreadB的任何操作happens-before于线程A从ThreadB.join()成功返回
写缓冲区
现代处理器使用写缓冲区临时保存向主存写入的数据,可以避免由于处理器向主存中写入数据而产生的延迟(对内存的读写速度远慢于处理器运行速度,对寄存器或者缓存的读写速度快于对)
数据依赖
JMM的重排序规则只会保证单线程的数据依赖正确
JMM只保证正确同步的并发操作是正确的(和顺序一致内存模型得到的结果相同)
顺序一致性内存模型
- 理想模型
- 一个线程中所有操作必须 按照程序顺序执行
- 每个操作原子执行,并且对所有线程立即可见(实际情况:没有原子执行,因为缓存也不能立即可见),因为立即可见,所以整体上所有线程看到的都是一个单一的执行顺序
Java 线程 — JMM Java内存模型的更多相关文章
- Java虚拟机学习 - 体系结构 内存模型
一:Java技术体系模块图 二:JVM内存区域模型 1.方法区 也称"永久代” .“非堆”, 它用于存储虚拟机加载的类信息.常量.静态变量.是各个线程共享的内存区域.默认最小值为16MB,最 ...
- Java虚拟机学习 - 体系结构 内存模型(1)
一:Java技术体系模块图 二:JVM内存区域模型 1.方法区 也称"永久代" ."非堆", 它用于存储虚拟机加载的类信息.常量.静态变量.是各个线程共享的内 ...
- Java虚拟机学习 - 体系结构 内存模型(转载)
一:Java技术体系模块图 二:JVM内存区域模型 1.方法区 也称"永久代” .“非堆”, 它用于存储虚拟机加载的类信息.常量.静态变量.是各个线程共享的内存区域.默认最小值为16MB, ...
- Java:JVM的内存模型
JVM内存模型 JVM内存模型可以分为两个部分,如下图所示,堆和方法区是所有线程共有的,而虚拟机栈,本地方法栈和程序计数器则是线程私有的. 1. 堆(Heap) 堆内存是所有线程共有的,可以分为两 ...
- java中JVM虚拟机内存模型详细说明
java中JVM虚拟机内存模型详细说明 2012-12-12 18:36:03| 分类: JAVA | 标签:java jvm 堆内存 虚拟机 |举报|字号 订阅 JVM的内部结构 ...
- 【java虚拟机】jvm内存模型
作者:pengjunlee原文链接:https://blog.csdn.net/pengjunlee/article/details/71909239 目录 一.运行时数据区域 1.程序计数器 2.J ...
- 第23章 java线程通信——生产者/消费者模型案例
第23章 java线程通信--生产者/消费者模型案例 1.案例: package com.rocco; /** * 生产者消费者问题,涉及到几个类 * 第一,这个问题本身就是一个类,即主类 * 第二, ...
- 【Java线程】Java内存模型总结
学习资料:http://www.infoq.com/cn/articles/Java-memory-model-1 Java的并发采用的是共享内存模型(而非消息传递模型),线程之间共享程序的公共状态, ...
- (转)【Java线程】Java内存模型总结
Java的并发采用的是共享内存模型(而非消息传递模型),线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信.多个线程之间是不能直接传递数据交互的,它们之间的交互只能通过共享变 ...
随机推荐
- Python笔记——break的注意事项
在python中有个控制流的语句:break 它是用来终止循环语句的,不管此时循环体进行到哪,只要碰到break都停止执行循环语句. 1.举例脚本: #!/usr/bin/env python for ...
- HttpServletRequest
javaweb学习总结(十)——HttpServletRequest对象(一) 一.HttpServletRequest介绍 HttpServletRequest对象代表客户端的请求,当客户端通过HT ...
- PHP 常用字符串函数整理
PHP语言中的字符串函数也是一个比较易懂的知识.今天我们就为大家总结了将近12种PHP字符串函数,希望对又需要的朋友有所帮助,增加读者朋友的PHP知识库. 1.查找字符位置函数 strpos($str ...
- Cacti的基本使用
对于Cacti是通过snmpget来获取数据,使用 RRDtool绘画图形,用snmp服务获取数据,然后用rrdtool储存和更新数据,那么就可以简单理解为Cacti就是RRDTool的一个web图形 ...
- MySQL数据库指定字符集
mysql 创建数据库时指定编码很重要,很多开发者都使用了默认编码,但是我使用的经验来看,制定数据库的编码可以很大程度上避免倒入导出带来的乱码问题. 我们遵循的标准是,数据库,表,字段和页面或文本的编 ...
- Eclipse中出现-访问限制由于对必需的库XX具有一定限制,因此无法访问类型
在项目上点击右键,找到构建路径.然后选择配置配置路径.按如下步骤来配置: 1 点击库选项 2把系统库扩展开来 3点击访问规则 4点击右边的添加按钮 5添加访问规则 6 分辨率设为可访问 7规则模式设为 ...
- NSString 的 compare 方法
- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange ...
- git -- 如何解决冲突
遇到冲突,首先要编辑冲突文件,可以使用vim或者其他工具,冲突文件变现为: <<<<HEAD 到 ==== :代表本地分支的修改内容 ==== 到 >>>&g ...
- WPF RichTextBox,关键字搜索,样式改变,超链接替换,图文混排
RichTextBox 只是一个控件,表示对 FlowDocument 对象执行操作的丰富编辑控件.它所承载的内容由其 Document 属性来呈现. Document 是一个 FlowDocumen ...
- [SmartFoxServer入门]服务器安装
安装SFS2X: SFS2X平台安装操作和步骤都很简单.我们建议先查看对系统的要求,然后根据你选择的操作系统按照指定的安装向导进行安装. 系统要求: SFS2X是一款支持所有主流操作系统,运行在JVM ...