持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第 7 天,点击查看活动详情
00、前言
“为什么 Thread 不能多次 start?”
“因为多次 start 多报错呀!”
“那会什么会报错?”
“因为不能多次 start 。”
.......
今天我们就来聊聊为什么一个线程为什么不能多次 start 呢?
如果尝试过多次 start 同一个线程的同学,都会得到一个异常——java.lang.IllegalThreadStateException。
01、分析
源码分析
首先我们直接来看看源码中是如何抛出这个异常的。
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
// Android-changed: Replace unused threadStatus field with started field.
// The threadStatus field is unused on Android.
if (started)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
// Android-changed: Use field instead of local variable.
// It is necessary to remember the state of this across calls to this method so that it
// can throw an IllegalThreadStateException if this method is called on an already
// started thread.
started = false;
try {
// Android-changed: Use Android specific nativeCreate() method to create/start thread.
// start0();
nativeCreate(this, stackSize, daemon);
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
可以源码中,是通过一个全局变量 started 去标识实现,当第一次调用完 start() 后,started 标识就会变为 true,当再次调用 start() 方法后,就会抛出异常。而对话中提出疑问的同学,应该是想知道源码中为什么要这么设计?那这个就需要提到线程的状态了。
线程状态
线程的状态有五种,分别为创建,就绪,运行中,阻塞和结束。它们之间的状态流转可能性,如下图所示。(注意:箭头的方向)
从图中我们可以看到,创建到就绪是一个单向的流转,即不可逆转,而 start 方法,正是将一个创建好了的线程状态标识为就绪状态,并加入到就绪队列中。处于就绪状态的线程,随时都可能被 CPU 调取执行。这就是源码要设计当我们多次对同一个线程调用 start() 时,抛出异常了。
02、结语
更多的线程状态内容,可以阅读菜鸟教程 - Java 线程的 5 种状态。