不论是继承Tread类创建线程还是实现Runnable接口创建线程,启动线程一般都是调用Thread类的start()方法,然后由虚拟机自动调用Thread类的run()方法,调用过程如下:
1.首先打开start()方法:
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();
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 */
}
}
}
start()方法调用了start0()方法,继续:
private native void start0();
start0()方法为native,网上搜索可得 JVM自动调用了run()方法,代码被封装了。
然后run()方法如下:
public void run() {
if (target != null) {
target.run();
}
}
自此,调用线程的过程分析完毕。
接下来看以下代码:
1.
public class ThreadDemo {
public static void main(String[] args) {
Thread thread = new Thread();
thread.start();
}
}
只是调用了最普通的线程类,没有任何打印输出。分析以上调用线程过程:
thread.start()调用后,会调用start0()方法,然后调用run()方法,由于该线程(thread)没有实现Thread类,只是最普通的线程类,所以也没有重写run()方法,所以只能调用JDK定义的Thread的run()方法,即:
public void run() {
if (target != null) {
target.run();
}
}
target为空,所以该run()方法什么也没有实现,所以没有任何输出(假定运行结果都是在控制台打印字符串)。
2.
public class ThreadDemo extends Thread {
public void run(){
System.out.println("自定义线程被调用");
}
public static void main(String[] args) {
ThreadDemo thread = new ThreadDemo();
thread.start();
}
}
该线程thread继承Thread类,并重写了run()方法,运行结果如下:
自定义线程被调用
由1情况分析可知:重写了run()方法,所以优先调用该run()方法
3.
public class ThreadDemo {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("执行的run()方法为Runnable接口实现");
}
}) .start();
}
}
该情况实现Runnable接口并且重写了run()方法,运行结果如下:
执行的run()方法为Runnable接口实现
分析run()方法调用可知:
public void run(){
if (target != null)
{ target.run();
}
}
此时target不为null,则会调用target.run()方法即我们自己重写的run()方法
4.
public class ThreadDemo {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("执行的run()方法为Runnable接口实现");
}
}) {
public void run() {
System.out.println("执行的run()方法为Thread类实现");
}
}.start();
}
}
该情况不仅Runnable接口重写了run()方法,而且Thread类也重写了run()方法
运行结果如下:
执行的run()方法为Thread类实现
分析调用过程:在调用run()方法时,如果重写了Thread类的run()方法,则会首先调用Thread类重写的run()方法
5.
public class ThreadDemo {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("执行的run()方法为Runnable接口实现");
}
}) {
public void run() {
System.out.println("执行的run()方法为Thread类实现");
super.run();
}
}.start();
}
}
仅仅增添了一句:super.run() 运行结果如下:
执行的run()方法为Thread类实现
执行的run()方法为Runnable接口实现
这个过程就有复杂了,但是还是慢慢分析:
首先调用Thread.start()方法,然后会调用Thread类中重写的run()方法,则输出:执行的run()方法为Thread类实现;
然后接着程序继续往下执行调用super.run(),super指超类即JDK定义的最基本的Thread类,然后调用JDK定义的Thread类的run()方法:
public void run() {
if (target != null) {
target.run();
}
}
此时target不为null,与第一种情况不同!然后会调用target的run()方法,即自己重写的Runnable接口的run()方法,输出为:执行的run()方法为Runnable接口实现
综合上述五种情况分析:
1.如果没有继承Thread类只是创建普通Thread类对象,则线程什么都不做
2.如果继承了Thread类:
a.如果重写了run()方法:则JVM调用该方法
b.如果没有重写run()方法:则JVM调用JDK自己定义的run()方法
I.如果指定了target,则调用target的run()方法
II.如果没有指定target,则什么都不做。
总结:
对于Thread(Runnable target).start()来说:不管target是否为空,Thread都会首先调用自己的run()方法:如果重写了该方法,且没有super.run(),则永远都不会调用Runnable中实现的run()方法;有super.run()的话,则首先调用完Thread自己的run()方法,然后决定是否再调用target中的run()方法;如果没有重写Thread自己的run()方法,则会判断target是否为空,然后决定是否调用target的run()方法。
分
析的可能有点乱,但仔细梳理上述几种情况的代码后,就会体会到。如有错误,欢迎指正。