Java内存模型(JMM)中的happens-before
happens-before是JMM中最核心的概念,对于Java程序员来说,理解happens-before是理解JMM的关键 。
1.JMM的设计
首先,来看看JMM的设计意图。从JMM的设计者的角度,在设计JMM时,需要考虑两个关键因素。
(1)程序员对内存模型的使用。程序员希望内存模型易于理解、易于编程,程序员希望基于一个强内存模型来编写代码。
(2)编译器和处理器对内存模型的实现。编译器和处理器希望内存模型对它们的束缚越少越好,这样它们就可以做尽可能多的优化来提高性能。编译器和处理器希望实现一个弱内存模型。
由于这两个因素互相矛盾,所以JSR-133专家组在设计JMM时的核心目标就是找到一个好 的平衡点:一方面,要为程序员提供足够强的内存可见性保证;另一方面,对编译器和处理器的限制要尽可能地放松。下面让我们来看看JSR-133是如何实现这一目标的。
double pi = 3.14 ; //A double r = 1.0 ; //B double area= pi*r*r; //C
上面计算圆的面积的示例代码存在3个happens-before关系如下 :
(1)A happens-before B
(2)B happens-before C
(3)A happens-before C
在3个happens-before关系中,2和3是必须的,但1是不必要的。因此,JMM把happens-before 要求禁止的重排序分为了下面两类 :
□ 会改变程序执行结果的重排序。
□ 不会改变程序执行结果的重排序。
JMM对这两种不同性质的重排序,采取了不同的策略,如下:
□ 对于会改变程序执行结果的重排序,JMM要求编译器和处理器必须禁止这种重排序。
□ 对于不会改变程序执行结果的重排序,JMM对编译器和处理器不做要求(JMM允许这种重排序) 。
下图是JMM的设计示意图:
从上图可以看出两点,如下。
□ JMM向程序员提供的happens-before规则能满足程序员的需求。JMM的happens-before 规则不但简单易懂,而且也向程序员提供了足够强的内存可见性保证(有些内存可见性保证并不一定真是存在,比如上面的A happens-before B) 。
□ JMM对编译器和处理器的束缚已经尽可能少。从上面的分析可以看出,JMM其实是在遵循一个基本原则:只要不改变程序的执行结果(指的是单线程程序和正确同步的多线程程序),编译器和处理器怎么优化都行。例如,如果编译器经过细致的分析后,认定一个锁只会被单个线程访问,那么这个锁可以被消除。再如,如果编译器经过细致分析后,认定一个volatile变量只会被单个线程访问,那么编译器可以把这个volatile变量当做是一个普通变量来对待。这些优化既不会改变程序的执行结果,又能提高程序的执行效率。
2.happens-before的定义
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)
· .NET 原生驾驭 AI 新基建实战系列(一):向量数据库的应用与畅想
· Ai满嘴顺口溜,想考研?浪费我几个小时
· Browser-use 详细介绍&使用文档
· 软件产品开发中常见的10个问题及处理方法