JMM到底如何理解?JMM与MESI到底有没有关系?

简介: 哈喽,我是子牙。十余年技术生涯,一路披荆斩棘从技术小白到技术总监到JVM专家到创业。技术栈如汇编、C语言、C++、Windows内核、Linux内核。特别喜欢研究虚拟机底层实现,对JVM有深入研究。分享的文章偏硬核,很硬的那种。手撸过JVM、内存池、垃圾回收算法、synchronized、线程池、NIO、三色标记算法…

哈喽,我是子牙。十余年技术生涯,一路披荆斩棘从技术小白到技术总监到JVM专家到创业。技术栈如汇编、C语言、C++、Windows内核、Linux内核。特别喜欢研究虚拟机底层实现,对JVM有深入研究。分享的文章偏硬核,很硬的那种。

手撸过JVM、内存池、垃圾回收算法、synchronized、线程池、NIO、三色标记算法…

erafbbd8u7.png

今天给大家分享一篇对于理解Java的多线程,特别重要的一个知识点:JMM。

在JVM中增加线程机制,首当其冲就是要实现JMM,即Java内存模型。JMM也是大家真正理解Java多线程的基础。但是大家对于JMM,可以说大多数小伙伴对其的理解是错误的。这篇文章我会从这几个方面讲JMM,让大家获得对JMM正确的、深刻的认识:
1、市面上大家看到的资料是怎么介绍JMM的
2、我会结合一个Linux多线程程序给大家分析,JMM与MESI没有半毛钱关系
3、那为什么要有JMM?不要行不行?
4、Java代码加或不加volatile对于可见性的影响如何理解?

正确认识JMM

有些小伙伴可能第一次听说JMM,大概介绍下:JMM即Java内存模型,不是JVM内存模型。Java的多线程机制是基于JMM实现的。如果你第一次听到这玩意是通过我这篇文章,那恭喜你,你还没有中毒。如果你还想进一步了解,接着往后看。

MESI即CPU的缓存一致性协议。现在取而代之的是MOESI。不同架构的CPU还有可能用其他的协议。理解本篇文章,了解到这个程度就够了,不展开讲。感兴趣的小伙伴可以自行面向百度学习。

你现在百度搜JMM,展示的文章基本都是这个套路:CPU缓存架构、计算机的内存模型、MESI、volatile实时触发数据一致性……不知道这套思路的始祖是谁,把一个简单的JMM讲得复杂得不行,正常人根本就看不懂,甚至被劝退。关键是错的,还能自圆其说地把这些名词串起来讲得像是真的一样。有多少小伙伴有同感的,留言区举个爪。

那如何正确理解JMM呢?一、不要把它与什么CPU、OS内存模型扯上关系。这些区域的数据一致性与JMM无关。可以想象有一堵墙,墙的一边是OS及硬件,另一边是JVM。JMM只与JVM有关,手没那么长,伸不到墙那边去;二、JMM你可以直接把它理解成工作内存+主内存;三、加或不加volatile跟触发MESI没有半毛钱关系,只是让JVM知道我要不要回写,伪代码如下

image.png

因为JMM是JVM自己抽象实现的,如果发生了写操作,正常情况工作内存与主内存的数据是不一致的。如果想告诉JVM我需要它一致,就得提供一套机制,这个机制就是volatile的一部分功能。

有两个名词解释一下:主内存,即共享内存,等同于JVM内存模型中的方法区+堆区。工作内存,即私有内存,等同于JVM内存模型中的虚拟机栈。

image.png

有些小伙伴可能就要说了:这些都是子牙老师你的个人认识,我们怎么知道是你的正确还是网上的那套呢?是的,没毛病(疯狂记仇)。熟悉我的小伙伴都知道,我要开始上证据了。名声稳不稳得住,就看证据给不给力了,求不翻车。

这个怎么解释

咱们来反证:如果CPU间的缓存一致、CPU缓存与内存间的数据一致需要通过volatile来触发,那操作系统线程间的数据可见性怎么触发?我们会写代码手动触发吗?上一段程序让大家感受下。

image.png

代码中没有任何触发机制,大家猜下:线程一sleep前后输出的结果是否都是10?上答案

image.png

答案是这次修改是线程可见的。为什么OS的线程天生具备线程可见性,而JMM不具备呢?这个画图不好说明,我将录制成视频放在B站。如果你没想明白,你想搞清楚,可以识别下方二维码观看。OS的线程可见性需要借助汇编说明。视频录制需要点时间,我会尽快录制的。

image.png

我感觉那些把JMM与MESI扯在一起的所谓大神,对底层真的一无所知。你但凡写个操作系统级别的多线程程序一测,就知道MESI还需要通过应用程序来触发,那是多么滑稽的一件事情。就像手机没有待机功能那么滑稽。

为什么要有JMM

同样来反证:不要JMM行不行?行?不行?答案是行!但是如果没有JMM,JVM就无法跨平台了,需要针对特定架构的操作系统开发线程机制。而且目前很多借助虚拟机栈实现的机制,比如synchronized的轻量级锁,可能实现起来就要更复杂一些了。

如果我们自己写程序,只针对特定的操作系统,比如Ubuntu,那不抽象实现JMM,直接基于操作系统的线程机制实现,会非常简单。但是我的手写JVM小班实现线程机制,还是与JVM保持一致,抽象实现了JMM。这样写一遍,将自己放在设计者的角度去思考,对于你阅读hotspot源码,会更有利。直接基于操作系统的线程机制去实现,好奇心重的小伙伴可以写一写,或许你能从中获得不一样的认知呢!

问个问题,看大家对本篇文章的内容理解得怎么样:那JMM与MESI可不可以有关系呢?大家留言回答吧。

我是子牙老师,喜欢钻研底层,深入研究Windows、Linux内核、JVM。如果你也喜欢研究底层,欢迎关注我的公众号【硬核子牙】

相关文章
|
2天前
|
存储 Java 编译器
Java内存模型(JMM)深度解析####
本文深入探讨了Java内存模型(JMM)的工作原理,旨在帮助开发者理解多线程环境下并发编程的挑战与解决方案。通过剖析JVM如何管理线程间的数据可见性、原子性和有序性问题,本文将揭示synchronized关键字背后的机制,并介绍volatile关键字和final关键字在保证变量同步与不可变性方面的作用。同时,文章还将讨论现代Java并发工具类如java.util.concurrent包中的核心组件,以及它们如何简化高效并发程序的设计。无论你是初学者还是有经验的开发者,本文都将为你提供宝贵的见解,助你在Java并发编程领域更进一步。 ####
|
4月前
|
存储 安全 Java
Java面试题:Java内存模型中的主内存与工作内存是如何协同工作的?请解释Java内存模型中的可见性、原子性和有序性,举例说明Java内存模型中的happens-before关系
Java面试题:Java内存模型中的主内存与工作内存是如何协同工作的?请解释Java内存模型中的可见性、原子性和有序性,举例说明Java内存模型中的happens-before关系
36 0
|
5月前
|
存储 安全 开发者
JMM的组成和它的作用
JMM的组成和它的作用
47 0
|
Java 编译器 程序员
JMM的内存可见性保证
JMM的内存可见性保证
51 0
|
存储 缓存 Java
高并发编程-通过volatile重新认识CPU缓存 和 Java内存模型(JMM)
高并发编程-通过volatile重新认识CPU缓存 和 Java内存模型(JMM)
277 0
|
缓存 安全 Java
《JUC并发编程 - 高级篇》04 -共享模型之内存 (Java内存模型 | 可见性 | 有序性 )(上)
《JUC并发编程 - 高级篇》04 -共享模型之内存 (Java内存模型 | 可见性 | 有序性 )
《JUC并发编程 - 高级篇》04 -共享模型之内存 (Java内存模型 | 可见性 | 有序性 )(上)
|
SQL 缓存 安全
《JUC并发编程 - 高级篇》04 -共享模型之内存 (Java内存模型 | 可见性 | 有序性 )(下)
《JUC并发编程 - 高级篇》04 -共享模型之内存 (Java内存模型 | 可见性 | 有序性 )
《JUC并发编程 - 高级篇》04 -共享模型之内存 (Java内存模型 | 可见性 | 有序性 )(下)
|
存储 安全 Java
JMM高并发详解(java内存模型、JMM三大特征、volatile关键字 )
JMM高并发详解(java内存模型、JMM三大特征、volatile关键字 )
JMM高并发详解(java内存模型、JMM三大特征、volatile关键字 )
JMM内存模型的读写过程(三)
JMM内存模型的读写过程
106 0
JMM内存模型的读写过程(三)
|
存储 Java 编译器
JMM内存模型的特性(二)
JMM内存模型学习
107 0
JMM内存模型的特性(二)