new Thread().start() 创建一个线程时,操作系统层面发生了什么?¶
题外话:这个问题是今年秋招作业帮出过的一道题,面试官问的还挺有水平的,其实这个问题考察的就是虚拟线程相关的问题,或者说是虚拟线程出来之前的平台线程的实现原理。因为涉及到一点操作系统底层了,所以不好回答。据说完全答对的几乎没有。
典型回答¶
new Thread().start()这个方法创建并启动线程的话,用的是平台线程,Java早期(JDK 21之前的线程,以及JDK 21之后不用虚拟线程的时候)的线程的是实现是靠操作系统内核线程来实现的,并且Java线程和OS内核线程之间是一对一的关系。
所以,操作系统层面,**new Thread()**主要是进行OS线程的创建,主要分以下四步:
分配内核线程¶
- 内核为新线程创建线程控制块(TCB),包含:
- 线程 ID(TID)
- 寄存器状态(PC、SP 等)
- 调度优先级
- 所属进程(共享地址空间、文件描述符等)
分配栈空间¶
- 用户态栈:默认大小由 JVM 控制(可通过
-Xss设置,如-Xss1m)。- 例如:Linux 上默认可能是 1MB(但实际是虚拟内存,按需分配物理页)。
- 内核栈:每个线程在内核中也有自己的栈(通常 8–16KB),用于系统调用。
设置初始上下文¶
- 程序计数器(PC)指向
thread_entry_point(JVM 的 C 入口函数)。 - 栈指针(SP)指向新分配的用户栈顶部。
加入调度器就绪队列¶
- 线程状态变为 RUNNABLE(可运行)。
- 由操作系统的调度器(如 Linux 的 CFS)决定何时在 CPU 上执行。
而**.start**方法的调用,则是线程的真正执行了:
- 新线程拿到CPU时间片
- 执行
thread_entry_point→ 初始化 JNI → 调用Thread.run()→ 最终执行你传入的Runnable.run()。