摘要: Java 的线程创建和启动非常简单,但如果问一个线程是怎么启动起来的往往并不清楚,甚至不知道为什么启动时是调用start(),而不是调用run()方法呢?
面试官:我考你个题,看看你进大厂的几率大不。嗯... Java 线程如何启动的?
谢飞机:如何启动的?start 启动的!
面试官:还有吗?
谢飞机:嗯…,没了!
面试官:嗯,可能会与不会这一个题并不会让你代码有多牛、有多好,但是你的技术栈深度和广度,决定你的编程职业生涯是否有一条康庄大道。还是要多努力!
一、线程启动分析
new Thread(() -> {
// todo
}).start();
咳咳,Java 的线程创建和启动非常简单,但如果问一个线程是怎么启动起来的往往并不清楚,甚至不知道为什么启动时是调用start(),而不是调用run()方法呢?
那么,为了让大家有一个更直观的认知,我们先站在上帝视角。把这段 Java 的线程代码,到 JDK 方法使用,以及 JVM 的相应处理过程,展示给大家,以方便我们后续逐步分析。
以上,就是一个线程启动的整体过程分析,会涉及到如下知识点:
- 线程的启动会涉及到本地方法(JNI)的调用,也就是那部分 C++ 编写的代码。
- JVM 的实现中会有不同操作系统对线程的统一处理,比如:Win、Linux、Unix。
- 线程的启动会涉及到线程的生命周期状态(RUNNABLE),以及唤醒操作,所以最终会有回调操作。也就是调用我们的 run() 方法
接下来,我们就开始逐步分析每一步源码的执行内容,从而了解线程启动过程。
二、线程启动过程
1. Thread start UML 图
如图 19-2 是线程的启动过程时序图,整体的链路较长,会涉及到 JVM 的操作。核心源码如下:
- Thread.c
- jvm.cpp
- thread.cpp
- os.cpp
- os_linux.cpp
- os_windows.cpp
- vmSymbols.hpp
2. Java 层面 Thread 启动
2.1 start() 方法
new Thread(() -> {
// todo
}).start();
// JDK 源码
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {}
}
}
- 线程启动方法 start(),在它的方法英文注释中已经把核心内容描述出来。Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread. 这段话的意思是:由 JVM 调用此线程的 ru