JUC源码讲解:逐步解析 Thread.start() 源码
JUC源码讲解:逐步解析 Thread.start() 源码
抛出问题
当 new Thread() 时,线程会进入 NEW 状态,如果我们想要使用线程,就需要调用 start() 方法,那么,在使用 star() 时发生了什么?有什么需要注意的?线程是怎么一步步被创建的?跟着我一起分析源码吧!
阅读源码
为了方便讲解,我先把源码贴出来,然后逐步讲解每一步的作用
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) {
}
}
}
我们先看这个方法头部分:
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
}
注意到了吧,是 sync!这是为了避免被多个线程同时启动!
这个if判断,如果线程状态是 NEW,threadStatus 才等于 0,其他状态的线程是不能被 star() 的,否则会抛出线程状态异常,if 是为了避免线程被重复 start
这里提一下,init后的线程状态是NEW
看下一段,加入 ThreadGroup
group.add(this);
最后一段值得一提:
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
变量 started 是线程的启动状态,注意到 try 块中的 start0() 方法了吗?这是个 native 方法,目的是启动线程,在 start0() 彻底结束之前,线程的状态都是 READY!执行成功后,只要线程拿到了CPU执行权,就是 RUNNING状态
在 finally 中,通过 started 判断 start0() 是否执行成功,如果没有成功,会调用 group.threadStartFailed(this);
我们点进去这个方法里看一下吧
void threadStartFailed(Thread t) {
synchronized(this) {
remove(t); // 删除该线程
nUnstartedThreads++; // start 失败的计数器
}
}
总结
-
start() 时为了避免线程被多次 start 而使用了 sync 和 if 。if保证非NEW状态的线程是不能被 start 的。sync方法保证不会被多个线程同时 start
-
在 start0() 执行完全成功之前,线程的状态是 READY,执行成功后,如果线程拿到了CPU执行权,状态会变为 RUNNING,他们都是 Thread.State.class 中的 RUNNABLE 状态
-
start 失败会将线程删除,并报错给父线程