java查看运行代码的汇编指令(含hsdis-arm64.dll文件)

    本文来自bilibili上的Java系列视频,需要额外的工具就是hsdis-arm64.dll文件。工具下载百度网盘链接:https://pan.baidu.com/s/1Q7kvS3a8YYXfaV3_OjNjBg 提取码:fvzm

    普通的Java代码执行,无法看到汇编指令,若要查看,需要下载hsdis动态链接库。一般网上介绍的都是mac下的hsdis.dylib,这里介绍是win10下的dll。

     这个工具需要放在jdk安装目录下的jre/bin目录下。

     运行代码的时候指定jdk为jre。

      准备一个Java代码:

package org.example;

public class VolatileVisibilityTest {
    private static volatile boolean initFlag = false;

    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            System.out.println("waiting data.....");
            while (!initFlag){

            }
            System.out.println("=========success.");
        }).start();

        Thread.sleep(2000);

        new Thread(()->prepareData()).start();

    }

    public static void prepareData(){
        System.out.println("prepare data end.");
        initFlag = true;
    }
}

    这个程序启动两个线程,一个线程依赖全局变量initFlag会做无限循环,直到initFlag发生改变,循环退出。另一个线程启动去尝试修改initFlag。一般认为,程序会依次打印waiting data,prepare data end,success信息,最后退出。实际上,如果不加volatile关键字,这个程序只是打印waiting data,prepare data end,并不会最终终止。

     

    以上代码,如果不加volatile关键字修饰,程序运行结果:

    线程运行在不同的CPU上,各自无法感知initFlag变量发生了改变,所以线程会挂住,一直在等待initFlag发生变化。

     当代码加上volatile关键字,程序运行结果如下所示:

    程序经历2秒之后,最终initFlag发生改变,所有线程均感知到,并退出while循环,打印success。最后主线程退出。

    idea下,点击Edit Configurations,弹出框中设置环境以及虚拟机参数:

虚拟机参数完整内容:

-server 
-Xcomp 
-XX:+UnlockDiagnosticVMOptions
-XX:+PrintAssembly
-XX:CompileCommand=compileonly,*VolatileVisibilityTest.prepareData

 运行结果截图:

   

volatile缓存可见性实现原理:

底层实现主要是通过汇编lock前缀指令,它会锁定这块内存区域的缓存,然后写入主内存。

IA-32和intel64架构软件开发者手册对lock指令的解释:

1)会将当前处理器缓存行的数据立即写回到系统内存

2)写回内存的操作会引起其他CPU缓存了该内存地址的数据无效(缓存一致性协议MSEI)

3) 提供内存屏障功能,使lock前后指令不能重排序


 

   通过上面的汇编指令查看工具,最后运行加了volatile关键字的代码就如前面那样,出现很多汇编指令。并且程序顺利终止。在大量的汇编指令中,我们可以看到如下片段:

 这个lock指令就是前面提到的volatile底层实现原理,他通过lock前缀指令锁定该内存,发生改变之后,立即写入主内存,其他缓存了该内存地址的CPU工作内存会失效,而需要读取主内存中的变量,所以程序最终按照预期完成所有操作并退出。

猜你喜欢

转载自blog.csdn.net/feinifi/article/details/121419456