写点什么

对线面试官 - 硬件级别之再谈 Volatile 关键字的可见性

作者:派大星
  • 2023-09-12
    辽宁
  • 本文字数:1688 字

    阅读完需:约 6 分钟

继之前讲多的Synchronized**volatile**关键字,本篇文章会再深入从硬件级别带你去了解其特性。


之前文章也有提到过:


Synchronized 既保证了原子性也保证了可见性、可重入(自己不停地加锁)volatile 主要是保证线程可见性,禁止指令重排序


文章参考:

https://mp.weixin.qq.com/s/UhBykeA14Jn9ACwv_QNoKA


面试官:你知道为什么 volatile 无法保证原子性。只可能保证可见性和有序性?


派大星:针对于 Volatile 关键字对原子性的保障在 Java 里是很有限的,我觉得几乎可以忽略不计。比如在 32 位的 Java 虚拟机里面,对 long、double 变量的赋值写不是原子性的,此时可以通过给变量加 Volatile 关键字来保证在 32 位 Java 虚拟机里面对 long、double 的赋值写是原子性的。相反int i = 0 原子性是 Java 语言规范(比如甲骨文)就规定了。


面试官:不错,那么为什么 long、double 在 32 位 Java 虚拟机里面的简单赋值操作不是原子性的。


派大星:所有变量的简单赋值操作,Java 语言规范都给你保证原子性的。但是例外的是long和double在32位虚拟机里面的简单赋值操作不是原子性的。因为long和double是64位的。如果多线程情况下同时并发执行 long = 30 ,由于 long 是 64 位的,就会导致有的线程在修改 l 的高 32 位,有的线程在修改 long 的低 32 位,多线程并发给 long 类型的变量进行赋值操作,在 32 位虚拟机是有问题的。产生的结果导致 a 的值不是 30,可能是-3333334430,也就是乱码一样的数字,因为高低 32 位赋值错了,就导致二进制转换为十进制之后是一个很奇怪的数字。


面试官:可以从硬件级别的谈一下可见性问题吗?或者说硬件级别为什么会有可见性问题?


派大星:好的。简单可从下面几种情况分析


  1. 每个处理器都有自己的一个寄存器(register),所以多个处理器各自运行一个线程的时候,会将主内存中的某个变量副本给加载到寄存器里面,然后对其进行更新。这样就会导致各个线程没法看到其它处理器里的变量值修改了。所以就引发了可见性的第一个问题:寄存器级别的变量副本的更新,无法让其它处理器看到

  2. 还有一个问题是,处理器运行的线程对变量的操作针对的都是写缓存(store buffer),并不是直接更新主内存,所以很可能导致一个线程更新了变量,但是仅仅只是在写缓存中进行了更新,并没有直接更新到主内存中去。这个时候其他线程也就无法读取到它的写缓冲区里面的变量值的。所以也导致了可见性的问题

  3. 每一个处理器都有自己的高速缓存,处理器运行的线程对变量的操作可能更新到写缓冲器里面,也可能更新到高速缓存中去或者是主内存中。但是其它处理器还是从自己的高速缓存或者写缓冲器中读取的变量值,此时还是读取的旧值,非新值。


面试官:既然硬件级别是有可见性问题的,那么是如何解决的呢?


派大星:硬件级别要想实现可见性,其中一个方法就是通过MESI协议。这个 MESI 协议在之前的文章也有提过但是并没有展开说。根据具体底层硬件的不同 ,MESI 协议的实现也是有些区别的。


面试官:可以简单说说 MESI 的实现方式吗?


派大星:可以的,MESI 协议实现如下:就是一个处理器将另外一个处理器的高速缓存中的更新后的数据拿到自己的高速缓存中来更新一下,这样彼此之间的缓存就实现了同步,然后各个处理器之间的线程看到的变量数据也就是一样的了。当然为了实现 MESI 协议,其中是有两个配套的专业机制的。flush 处理器缓存refresh处理器缓存


  • 首先说一下flush处理器缓存其目的是把自己更新的变量值刷新到高速缓存里(或主内存中去),并且它还会发送一个消息到总线(bus),通知其它处理器某个变量值被它更新了。这样才可让其它的处理器从自己的高速缓存(主内存)里读取到更新的值。

  • 其次就是refresh处理器缓存,它的目的是处理器中的线程在读取一个变量的时候,如果发现总线(bus)嗅探中有消息说其他处理器的线程更新了该变量的值,则必须从其它处理器的高速缓存(或主内存)中读取到这个最新的值,并更新到自己的高速缓存中去


总的来说,为了保证可见性,在底层是通过MESI协议flush处理器缓存refresh处理器缓存,这一套机制来保障的。并且其实内存屏障的使用,在底层硬件级别的原理,其实就是在执行flushrefresh


如有问题,欢迎加微信交流:w714771310,备注- 技术交流  。或关注微信公众号【码上遇见你】。




发布于: 刚刚阅读数: 3
用户头像

派大星

关注

微信搜索【码上遇见你】,获取更多精彩内容 2021-12-13 加入

微信搜索【码上遇见你】,获取更多精彩内容

评论

发布
暂无评论
对线面试官 - 硬件级别之再谈Volatile关键字的可见性_Java 面试题_派大星_InfoQ写作社区