Java 线程运行的原理

247 阅读2分钟

一、JVM 中的线程

我们都知道 JVM 是由堆、栈、方法区所组成,其中栈内存是给谁用的呢?其实就是线程,每个线程启动后,虚拟机就会为其分配一块栈内存。

  • 每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存
  • 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法。

下面先看一段只有主线程的代码,分析内存图:

/**
 * 测试栈帧
 * @author 落霞不孤
 */
public class TestFrames {
    public static void main(String[] args) {
        // Thread t1 = new Thread(() -> {method1(20);}, "t1");
        // t1.start();
        method1(10);
    }

    private static void method1(int x) {
        int y = x + 1;
        Object m = method2();
        System.out.println(m);
    }

    private static Object method2() {
        Object n = new Object();
        return n;
    }
}

运行这段代码,JVM 首先开启一个 main 的线程栈空间,里面由程序计数器(记录程序执行的行数)和栈帧(每调用一个方法就生成一个栈帧)构成。其中栈帧内部由局部变量表、锁记录、返回地址、操作数栈等等,我们中间 new 的对象在堆上面,这个过程如下图所示:

如果由 main 方法中多个线程,那么内存分布图变为下图: image-20210305144853435 和只有一个线程的图差不多,每个线程都维护了一个程序计数器,因此当发生线程上下文切换的时候 CPU 就可以知道每个线程执行到哪一步。

二、IDEA 中调试多线程的程序

  1. 在线程定义位置打下断点,断点处右键选择 Thread 模式

  2. 启动 Debug 模式,调试的步骤和普通的程序调试一样,在 DeBug 窗口,我们可以观察到有两个线程在运行

  3. main 线程执行完毕,我们可以切换到 t1 线程,可以发现,它并没有随着主线程的结束而结束

  1. 当两个线程都结束以后,整个程序才是真正地结束了。