专栏首页HUC思梦的java专栏从硬件级别再看可见性和有序性

从硬件级别再看可见性和有序性

前言

王子之前的文章对于并发编程中的可见性问题已经有了一个初步的介绍,总结出来就是CPU的缓存会导致可见性问题

这样的解释其实是没有问题的,但这里说的“缓存”其实一个笼统的概念,缓存其实指的是寄存器、高速缓存和写缓冲器

今天我们就从硬件的级别再来探索一下出现可见性问题的原因,让小伙伴们有一个更深的认识。

同时再深入探索一下有序性问题的产生原因。

如果小伙伴们对于寄存器、高速缓存、缓冲器、总线的概念还不清楚,建议自行去查阅资料了解。

出现可见性问题的原因

首先,我们知道每个CPU都有自己的寄存器,它用于存储临时的二进制数据,做一些数据运算。

所以当多个CPU各自运行一个线程的时候,就会导致在寄存器中对数据的修改对其他CPU是不可见的。

然后,一个CPU对变量的写操作都是针对写缓冲器的,并不是直接把值写到主内存中。

所以没有写到主内存中的数据,对其他CPU是不可见的。

然后写入缓冲器后,会把更新后的数据写入到高速缓存中,之后把变量更新信息通过总线通知给其他CPU,但是其他CPU可能会认为这个更新是无效的,不会更新它自己的高速缓存数据,这就导致了高速缓存的可见性问题。

整体的内存模型如图:

MESI协议解决可见性

解决可见性问题的一种方案就是MESI协议,这个MESI协议,根据不同的硬件系统,会有不同的实现方式。

比如MESI的一种实现方式,就是CPU接收到变量更新的消息后,直接更新数据到自己的高速缓存中,这样各个CPU高速缓存中的数据就一致了,解决了可见性问题。

说到MESI协议,王子要跟大家说两个新名词,flush和refresh。

先来说一下flush。

flush就是把自己更新的值刷新到高速缓存(或主内存)中,除了flush操作,同时还会发送一个消息到总线(bus),通知其他处理器某个变量值被修改了。

那refresh又是什么呢?

refresh指的是,处理器中的线程在读取某个变量的时候,如果发现其他处理器的线程修改了这个变量,那就必须过期掉自己高速缓存中的值,从其他处理器的高速缓存(或主内存)中读取变量,同步到自己的高速缓存中。

这就是MESI协议最最基础的原理。

探索有序性问题

之前的文章我们已经说过,指令重排会导致有序性问题,那么具体什么时候会发生指令重排呢?这就要从代码的编译过程说起了。

首先我们写的java代码会被javac静态编译器进行编译,编译成class字节码,然后会经过JIT动态编译器编译成操作系统可以执行的机器码,在编译的过程中,有一个编译优化的概念,为了提高执行效率,可能会发生指令重排,例子就是之前文章中我们说到的double check单例模式,这里就不再说明了。

除了编译会发生指令重排,CPU本身也可能改变指令的执行顺序,另外高速缓存、写缓冲器和无效队列在硬件层面也可能会改变指令的顺序。

接着我们来探索一下CPU是如何出现指令重排的?这就涉及到CPU的指令乱序和猜测执行机制了。

首先我们来看一下指令乱序机制。

CPU获取到的指令是不一定能直接执行的,比如指令要执行网络通信、磁盘IO、获取锁等,为了提升效率,CPU使用的就是指令乱序机制。

把编译好的指令一条一条的读取到处理器中,但哪条指令先就绪可以执行了,就会先执行,而不会去按照顺序执行。

然后将指令执行后的结果放入指令重排序处理器中,重排序处理器再把这些结果按照最开始的指令顺序同步到主内存或写缓冲器中。

这就是指令乱序机制,可能出现有序性问题。

除此之外还有一个猜测执行机制,比如if判断后,执行一堆代码,可能先去执行这堆代码,然后再进行判断,如果判断成立,就采纳执行的结果,否则不采纳执行的结果,这种机制也可能出现有序性问题。

说完了cpu,再来看看高速缓存、写缓冲器是如何导致内存重排序的

首先来了解两个概念,storeload

store指的是处理器将数据写入写缓冲器这一过程,load指的是处理器从高速缓存里读数据这一过程。这两个过程可能导致内存重排序,一共有四种可能:

LoadLoad重排序:一个处理器先执行L1,后执行L2,另一个处理器可能看到的是先执行L2,后执行L1;

StoreStore重排序:一个处理器先执行W1,后执行W2,另一个处理器可能看到的是先执行W2,后执行W1;

LoadStore重排序:一个处理器先执行L1,后执行W2,另一个处理器可能看到的是先执行W2,后执行L1;

StoreLoad重排序:一个处理器先执行W1,后执行L2,另一个处理器可能看到的是先执行L2,后执行W1;

为了便于理解,以StoreStore重排序为例,假如高速缓存按照W1W2的顺序接收到两个操作,为了提高性能,先执行了W2,后执行了W1,这就发生了内存重排序,其他处理器看到的顺序就是重新排序后的顺序。

总结

今天我们从硬件级别重新认识了一下可见性和有序性问题。

对于可见性,我们介绍了CPU的缓存机制和MESI协议。

对于有序性,我们介绍了编译优化、CPU的指令乱序和猜测执行、内存重排序机制导致的指令重排问题。

这就是全部内容了,希望小伙伴们能够通过对底层原理的理解,更容易的理解并发编程。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java内存模型:看Java如何解决可见性和有序性问题

    你已经知道,导致可见性的原因是缓存,导致有序性的原因是编译优化,那解决可见性、有序性最直接的办法就是禁用缓存和编译优化,但是这样问题虽然解决了,我们程序的性能可...

    慕容千语
  • java 轻量级同步volatile关键字简介与可见性有序性与synchronized区别 多线程中篇(十二)

    JMM规范解决了线程安全的问题,主要三个方面:原子性、可见性、有序性,借助于synchronized关键字体现,可以有效地保障线程安全(前提是你正确运用)

    noteless
  • 硬盘是如何影响数据库性能的?

    松哥原创的 Spring Boot 视频教程已经杀青,感兴趣的小伙伴戳这里-->Spring Boot+Vue+微人事视频教程

    江南一点雨
  • 硬件内存模型到 Java 内存模型,这些硬核知识你知多少?

    Java 内存模型跟上一篇 JVM 内存结构很像,我经常会把他们搞混,但其实它们不是一回事,而且相差还很大的,希望你没它们搞混,特别是在面试的时候,搞混了的话就...

    Bug开发工程师
  • 硬件内存模型到 Java 内存模型,这些硬核知识你知多少?

    Java 内存模型跟上一篇 JVM 内存结构很像,我经常会把他们搞混,但其实它们不是一回事,而且相差还很大的,希望你没它们搞混,特别是在面试的时候,搞混了的话就...

    Java_老男孩
  • 你真的知道Java内存模型是什么吗

    前几天,发了一篇文章,介绍了一下JVM内存结构、Java内存模型以及Java对象模型之间的区别。有很多小伙伴反馈希望可以深入的讲解下每个知识点。Java内存模型...

    格姗知识圈
  • 轻松理解计算机的内存模型及Java内存模型

    本文转载自:https://www.hollischuang.com/archives/2550

    aoho求索
  • Windows Server分布式存储深入解析(课程实录)

    我们今天的主题是Windows Server 存储空间的I/O分发,主要包括以下两种情况下的I/O分发:

    盆盆
  • Java后端开发岗必备技能:Java并发中的内存模型

    JMM通过构建一个统一的内存模型来屏蔽掉不同硬件平台和不同操作系统之间的差异,让Java开发者无需关注不同平台之间的差异,达到一次编译,随处运行的目的,这也正是...

    慕容千语
  • 朱建平:如何架构海量存储系统

    5月25日,云+社区技术沙龙-互联网架构成功举办。本期沙龙特邀请腾讯的技术专家分享关于技术架构、落地实践案例、无服务器云函数架构、海量存储系统架构等话题,从技术...

    云加社区技术沙龙
  • 高级语言,高级在哪?

    高级语言、低级语言,都是对计算机而言。人类语言不存在这种说法。 在上篇文章(一分钟认识你的电脑)中,柚子向大家介绍了内存。 内存的最小单位是bit,二进制表示,...

    企鹅号小编
  • 死磕 java同步系列之JMM(Java Memory Model)

    Java内存模型是在硬件内存模型上的更高层的抽象,它屏蔽了各种硬件和操作系统访问的差异性,保证了Java程序在各种平台下对内存的访问都能达到一致的效果。

    彤哥
  • 不好意思,我和 Java 内存模型杠上了!

    Java内存模型是在硬件内存模型上的更高层的抽象,它屏蔽了各种硬件和操作系统访问的差异性,保证了Java程序在各种平台下对内存的访问都能达到一致的效果。

    zhisheng
  • Java内存模型 - JMM

    Java语言的其中一个特点为跨平台性即由Java编写的程序,一次编译后就可以在多个系统平台上运行。

    虞大大
  • 简谈Xilinx Zynq-7000嵌入式系统设计与实现

    大侠好,欢迎来到FPGA技术江湖,江湖偌大,相见即是缘分。大侠可以关注FPGA技术江湖,在“闯荡江湖”、"行侠仗义"栏里获取其他感兴趣的资源,或者一起煮酒言欢。...

    FPGA技术江湖
  • Java后端开发岗必备技能:Java并发中的内存模型

    JMM通过构建一个统一的内存模型来屏蔽掉不同硬件平台和不同操作系统之间的差异,让Java开发者无需关注不同平台之间的差异,达到一次编译,随处运行的目的,这也正是...

    欧阳愠斐
  • 如何为 MySQL 选择 CPU?

    MySQL 服务器性能受制于整个系统最薄弱的环节,承载它的操作系统和硬件往往是限制因素。磁盘大小、可用内存和 CPU 资源、网络,以及所有连接它们的组件,都会限...

    博文视点Broadview
  • linux磁盘简介

    现在磁盘最常用的可简单分为普通的机械盘和SSD(Solid-state drive或Solid-state disk)两种,他们都已不同的接口协议和主板链接,在...

    用户1516716
  • 第十五章 系统服务管理

    服务是什么?先来看一下服务的定义:一台主机上提供的、运行的各种功能统称为服务。有本机内服务,如:at,cron,有对外的网络服务,如:web、ftp等,又称为...

    晓天

扫码关注云+社区

领取腾讯云代金券