文章目录
启动线程的正确和错误方式
start()和run()的比较
public class StartAndRunMethod {
public static void main(String[] args) {
Runnable runnable = () -> {
System.out.println(Thread.currentThread().getName());
};
runnable.run();
new Thread(runnable).start();
}
}
打印结果:
main
Thread-0
我们会发现,runnable.run()方法是由main线程执行的,而要子线程执行就一定要先调用start()启动新线程去执行。
start()方法原理解读
- 方法含义
- 启动新线程
- 准备工作
- 不能重复调用start
public class CantStartTwice {
public static void main(String[] args) {
Thread thread = new Thread();
thread.start();
thread.start();
}
}
结果:
Exception in thread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:705)
at com.hd.thread.start.CantStartTwice.main(CantStartTwice.java:14)
抛出非法的线程异常。
- 源码解析
- 启动新线程检查线程状态
- 加入线程组
- 调用start0
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".
*/
if (threadStatus != 0) //启动新线程检查线程状态
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); //加入线程组
boolean started = false;
try {
start0(); //调用start0
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 */
}
}
}
- 深入JDK源码
- start0()是一个本地方法
run()方法原理解读
- 源码解析
- 两种情况
@Override
public void run() {
if (target != null) {
target.run();
}
}
面试问题
1.一个线程两次调用start方法会出现什么情况?为什么?
会抛出非法线程状态异常,在start()方法里面,一开始就会进行启动新线程检查线程状态
。
2.既然start方法会调用run方法,为什么我们选择调用start方法,而不是直接调用run方法呢?
因为调用start方法才是真正意义上的启动一个线程,它会去经历线程的各个生命周期,如果调用run方法,它仅仅是一个普通方法而已,不会用子线程调用。
3.start方法的执行流程是什么?
- 检查线程状态,只有NEW状态下的线程才能继续,否则会抛出IllegalThreadStateException异常(在运行中或者已结束的线程,都不能再次启动)。
- 被加入线程组。
- 调用start0方法启动线程。
- 注意点:
- start方法是被synchronized修饰的方法,可以保证线程安全;
- 由JVM创建的main方法线程和system组线程,并不会通过start来启动。
笔记来源:慕课网悟空老师视频《Java并发核心知识体系精讲》