1.实验:模拟Java线程状态迁移过程

在《【运行时数据区】-并发编程-前置知识(4.并发编程基础)-6》中,我们分析了Java线程从JDK层面到JVM层面的状态迁移:

image-20230414070017806

本文我们来尝试自己实现Java线程的状态迁移过程,进一步加深对这个状态迁移过程的理解。

2.简化:JVM调用链

  • 如下是JVM调用链:

image-20230414064052581

  • 我们简化调用链如下:

image-20230422145647662

3.模拟1:JVM注册JNI接口

  • 如红框处,我们通过System.load方法,加载提供了JNI接口的动态库lib.so文件。

image-20230422135359625

4.模拟2:启动Java线程

如下图:

  • start()方法模拟JDK的Thread.start()方法,该方法调用了start0()方法。
  • start0()方法模拟JDK的Thread.start0()方法,该方法为JNI接口。

image-20230422135522197

  • 通过javah,我们生成了start0()方法对应的C++头文件。

image-20230422135555599

6.模拟3:创建native线程

  • start0()方法的实现中,我们调用了pthread_create()方法,创建native线程。

image-20230422135727912

7.模拟4:等待

  • 当CPU调度上一步我们创建的native线程,进入该线程的回调函数java_start()
  • 我们创建了标志位flag,它用于模拟JVM中记录native线程一系列状态的标志位,初始值为0,表示native线程处于INITIALIZED状态。
  • while循环导致native线程一直处于等待状态。

image-20230422135917734

8.模拟5:打破循环

  • 回到start0方法的实现,通过sleep了一段时间后修改flag标志位,模拟JVM中经过一系列准备工作,将native线程设置为RUNNABLE状态
  • 此时,native线程在java_start()中处于循环等待的状态被打破。

image-20230422135949723

9.模拟6:回调JDK

  • 当native线程在java_start()中处于循环等待的状态被打破后,通过JNI获得Java侧的Test对象,进一步回调Java侧Test对象的run()方法。
  • 这一步,就模拟了JVM在native线程变为RUNNABLE状态后回调JDK的Thread.run()方法。

image-20230422140058781

image-20230422140113451

10.运行效果

  • 运行我们的模拟程序,打印结果如下:

image-20230422140522662

  • 本次实验,最终模拟了JDK中创建Java线程,JVM中对应也创建native线程,native线程的状态迁移后回调Java线程的回调函数。

image-20230422153048716