JMM到底如何理解?JMM与MESI到底有没有关系?
哈喽,我是子牙。十余年技术生涯,一路披荆斩棘从技术小白到技术总监到JVM专家到创业。技术栈如汇编、C语言、C++、Windows内核、Linux内核。特别喜欢研究虚拟机底层实现,对JVM有深入研究。分享的文章偏硬核,很硬的那种。
手撸过JVM、内存池、垃圾回收算法、synchronized、线程池、NIO、三色标记算法…
今天给大家分享一篇对于理解Java的多线程,特别重要的一个知识点:JMM。
在JVM中增加线程机制,首当其冲就是要实现JMM,即Java内存模型。JMM也是大家真正理解Java多线程的基础。但是大家对于JMM,可以说大多数小伙伴对其的理解是错误的。这篇文章我会从这几个方面讲JMM,让大家获得对JMM正确的、深刻的认识:
1、市面上大家看到的资料是怎么介绍JMM的
2、我会结合一个Linux多线程程序给大家分析,JMM与MESI没有半毛钱关系
3、那为什么要有JMM?不要行不行?
4、Java代码加或不加volatile对于可见性的影响如何理解?
有些小伙伴可能第一次听说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知道我要不要回写,伪代码如下
因为JMM是JVM自己抽象实现的,如果发生了写操作,正常情况工作内存与主内存的数据是不一致的。如果想告诉JVM我需要它一致,就得提供一套机制,这个机制就是volatile的一部分功能。
有两个名词解释一下:主内存,即共享内存,等同于JVM内存模型中的方法区+堆区。工作内存,即私有内存,等同于JVM内存模型中的虚拟机栈。
有些小伙伴可能就要说了:这些都是子牙老师你的个人认识,我们怎么知道是你的正确还是网上的那套呢?是的,没毛病(疯狂记仇)。熟悉我的小伙伴都知道,我要开始上证据了。名声稳不稳得住,就看证据给不给力了,求不翻车。
这个怎么解释咱们来反证:如果CPU间的缓存一致、CPU缓存与内存间的数据一致需要通过volatile来触发,那操作系统线程间的数据可见性怎么触发?我们会写代码手动触发吗?上一段程序让大家感受下。
代码中没有任何触发机制,大家猜下:线程一sleep前后输出的结果是否都是10?上答案
答案是这次修改是线程可见的。为什么OS的线程天生具备线程可见性,而JMM不具备呢?这个画图不好说明,我将录制成视频放在B站。如果你没想明白,你想搞清楚,可以识别下方二维码观看。OS的线程可见性需要借助汇编说明。视频录制需要点时间,我会尽快录制的。
我感觉那些把JMM与MESI扯在一起的所谓大神,对底层真的一无所知。你但凡写个操作系统级别的多线程程序一测,就知道MESI还需要通过应用程序来触发,那是多么滑稽的一件事情。就像手机没有待机功能那么滑稽。
为什么要有JMM同样来反证:不要JMM行不行?行?不行?答案是行!但是如果没有JMM,JVM就无法跨平台了,需要针对特定架构的操作系统开发线程机制。而且目前很多借助虚拟机栈实现的机制,比如synchronized的轻量级锁,可能实现起来就要更复杂一些了。
如果我们自己写程序,只针对特定的操作系统,比如Ubuntu,那不抽象实现JMM,直接基于操作系统的线程机制实现,会非常简单。但是我的手写JVM小班实现线程机制,还是与JVM保持一致,抽象实现了JMM。这样写一遍,将自己放在设计者的角度去思考,对于你阅读hotspot源码,会更有利。直接基于操作系统的线程机制去实现,好奇心重的小伙伴可以写一写,或许你能从中获得不一样的认知呢!
问个问题,看大家对本篇文章的内容理解得怎么样:那JMM与MESI可不可以有关系呢?大家留言回答吧。
我是子牙老师,喜欢钻研底层,深入研究Windows、Linux内核、JVM。如果你也喜欢研究底层,欢迎关注我的公众号【硬核子牙】
基础篇:深入JMM内存模型解析volatile、synchronized的内存语义 总线锁定:当某个CPU处理数据时,通过锁定系统总线或者是内存总线,让其他CPU不具备访问内存的访问权限,从而保证了缓存的一致性
深入分析java内存模型(注意和java内存结构的区别) 最近在更java多线程相关的文章,正好有人问我一些java内存模型的问题,因此花了一些时间,好好地了解一下。本篇文章主要是为了解决以下几个问题? 1、java内存模型和java内存结构有什么区别? 2、为什么要有内存模型? 3、java的内存模型是什么样子的? 这篇文章,基本上不会涉及到代码,全是一些概念性的知识,但是也是面试常问和java进阶所需要掌握的必要的基本知识点,所以,希望你耐着性子,慢慢来。
相关文章
- 结巴分词自定义词库中“词频”如何理解,有什么作用?
- 如何快速理解一个全新的嵌入式操作系统(续)(转载)
- 如何快速理解一个全新的嵌入式操作系统(转载)
- 如何理解C4.5算法解决了ID3算法的偏向于选择取值较多的特征问题
- 如何设置 Ubuntu14.04 的 SSH 无密码登录
- grep 命令系列:如何在 Linux/UNIX 中使用 grep 命令
- 一文理解Kafka如何做到高吞吐
- 网络安全架构:如何理解P2DR模型
- 如何理解快速排序的时间复杂度是O(nlogn)
- Qt Model/View理解(二)---构造model(细心研读,发现超简单,Model就是做三件事:返回行数量、列数量、data如何显示。然后把model与view联系起来即可,两个例子都是如此)good
- django python如何安装以及启动虚拟机
- Martin Fowler谈如何理解事件驱动
- 浅析css-loader和style-loader的作用、css-loader和style-loader是如何配合使用的、less-loader和css-loader和style-loader的实现原理
- 如何使用快应用内置地图查看、导航位置
- 如何理解链表与数组呢?
- 如何理解大数据分析
- iOS开发 - 系统导航栏左右上角按钮如何不需要定义就可以添加小红点
- nginx学习笔记(7)Nginx如何处理一个请求---转载
- 如何将设备添加到电气CAD图库中?电气CAD图库设备添加步骤
- 暖通CAD设计中如何修正外墙?
- CAD软件中如何管理负荷对象模板?
- 如何理解深度学习中的embedding?