学习Java内存模型JMM心得
作者:钟绍威 发布时间:2023-11-28 20:56:17
有时候编译器、处理器的优化会导致runtime与我们设想的不一样,为此Java对编译器和处理器做了一些限制,JAVA内存模型(JMM)将这些抽象出来,这样编写代码时就无需考虑那么多底层细节,并保证“只要遵循JMM的规则编写程序,其运行结果一定是正确的”。
JMM的抽象结构
在Java中,所有的实例、静态变量存储在堆内存中,堆内存是可以在线程间共享的,这部分也称为共享变量。而局部变量、方法定义参数、异常处理参数是在栈中的,栈内存不在线程间共享。
而由于编译器、处理器的优化,会导致共享变量出现可见性问题,像在多核处理器中(multi-processor),线程可以在不同的处理器上执行,而处理器之间缓存不一致,会使共享变量出现可见性问题,有可能两个线程看到同一个变量不同值。
JMM将这些硬件做的优化抽象成每个线程都有一个本地内存。需要读写共享变量时,从主内存中拷贝一份到本地内存。当写共享变量时,先写到本地内存中去,在将来某个时间再刷新到主内存中。当再次读共享变量时,则只会从本地内存中读取。
这样线程间通讯就需要经过两步:
写线程:刷新本地内存到主内存中去读线程:从主内存读取更新后的值
这样在写-读之间就有一个延迟:本地内存什么时候刷新到主内存中去?导致可见性问题,不同线程可能看到的共享变量不一样。
happens-before
从字面上看happens-before的意思是“发生在此之前”。这是java对程序执行顺序制定的规则,实现同步必须遵循该规则。这样程序员只需要写出正确的同步程序,happens-before保证运行结果不会错。
A happens-before B,不仅仅表示A在B之前执行,还意味着A的执行结果对B可见,这保证了可见性。
A happens-before B,A也不一定要在B之前执行,如果AB交替,执行结果任然正确,则允许编译器、处理器进行优化重排序。所以只要程序结果正确,编译器、处理器怎么优化,怎么重排序都没问题,都是好的。
happens-before规则
程序顺序规则:在一个线程中,前面的操作happens-before后面的操作锁规则:对同一个锁,解锁happens-before加锁 volatile域规则:写volatile变量,happens-before后面任意一个读这个volatile变量的操作传递性:A happens-before B,B happens-before C,则A happens-before C start()规则:如果线程A执行ThreadB.start() 那么ThreadB.start() happens-before 线程B中任何操作 join()规则:如果线程A执行ThreadB.join(),那么线程B中的所有操作happens-before ThreadB.join()
下面这个示例有助于理解happens-before
double pi = 3.14; //A
double r = 1.0; //B
double area = pi * r *r; //C
这里有三个happens-before关系,规则1、2是程序顺序规则,规则3是传递性规则推导出来的:
A happens-before B B happens-before C A happens-before C
C依赖于A、B,但是A和B谁也不依赖。所以即使A和B重排序,执行结果也不会发生变化,这种重排序,JMM是运行的。
下面两种执行顺序的结果都是正确的。
来源:http://www.cnblogs.com/wewill/p/8081394.html
猜你喜欢
- 背景2022国家级护网行动即将开启,根据阿里云给出的安全建议,需要将登陆Linux的方式改为密钥对方式。我这里使用的远程工具是自己开发的,能
- 在编写脚本的过程中我们会遇到一些小问题比如一个的变量 为了在其他脚本中可以调用 我们需要写成public类型的这样的话在Inspector面
- 前提:当我们使用Winform开发的时候,经常会遇到:System.InvalidOperationException:&ldquo
- 本人是从事互联网金融行业的,所以会接触到一些金融类的问题,常见的一种就是数字转汉字大小写的问题。所以抽空就写了一个小小的工具类,实现了数字转
- 在 MyEclipse 的可视化 Swing 中,有 JTable 控件。JTable 用来显示和编辑常规二维单元表。那么,如何将 数据库S
- 目录前言应用定义基本Enum特性Enum的静态导入Enum中添加新方法Switch语句中的EnumEnum的继承EnumSet的使用Enum
- 一、容器初始化1、源码分析在jdk8的ConcurrentHashMap中一共有5个构造方法,这四个构造方法中都没有对内部的数组
- 引言什么?兔了个兔?吐了还要吐?首先今天,我们自己用android程序实现一个兔年的新年贺卡。下面就是见证美好的时刻,上效果。好,我们来使用
- 本文实例讲述了Android弹出窗口实现方法。分享给大家供大家参考,具体如下:直接上代码:/*** 弹窗--新手指引* @param cxt
- 1.首先,需要指定获取的文件夹,以及获取文件的文件名;文件夹:strLocalPath = System.Windows.Forms.App
- 写在前面元旦三天在家闲着无事,就看了看Linq的相关内容,也准备系统的学习一下,作为学习Linq的前奏,还是先得说说Lambda与匿名方法的
- 设置项这个版本已经取消了defalut settings指定成默认配置的选项,所以配置都是在settings中配置设置项设置统一UTF-8编
- 部分情况下无法通过maven仓库直接下载需要的jar包,只能讲jar包下载至本地来使用,spring boot框架内通过maven加载第三方
- 下文笔者讲述StringTokenizer对象的简介说明,如下所示StringTokenizer的简介Java StringTokenize
- 1、ThreadLocal 使用原理前文我们讲过ThreadLocal的主要用途是实现线程间变量的隔离,表面上他们使用的是同一个Thread
- 本文实例为大家分享了Java实现颜色渐变效果的具体代码,供大家参考,具体内容如下RGB色彩,在自然界中肉眼所能看到的任何色彩都可以由红(R)
- 1. 简单说明嗨,大家好!今天给大家分享的是Mybatis-plus 插件的分页机制,说起分页机制,相信我们程序员都不陌生,今天,我就给大家
- 本文实例讲述了Java删除二叉搜索树最大元素和最小元素的方法。分享给大家供大家参考,具体如下:在前面一篇《Java二叉搜索树遍历操作》中完成
- Dialog和Toast所有人肯定都不会陌生的,这个我们平时用的实在是太多了。而Snackbar是Design Support库中提供的新控
- 使用spring框架实现数据库事务处理事务对于数据库来说是,是对sql语句的一系列操作,这些操作被组织成为一个事务。事务具有原子性的,要么全