感觉有点标题党了。今天看网上的一个文章,发现的问题。
原文如下:
如果在Thread子类覆盖的run方法中编写了运行代码,也为Thread子类对象传递了一个Runnable对象,那么,线程运行时的执行代码是子类的run方法的代码?还是Runnable对象的run方法的代码?
作者的观点是这个涉及到“匿名内部类对象的构造方法如何调用父类的非默认构造方法”这个知识点。先不管对不对,分析再说,下面是这个作者有的代码
private static void threadTest3() {
Thread thread3=new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i=0; i < 1000; i++) {
System.out.println("Runnable: " + i + Thread.currentThread().getName());
}
}
}) {
@Override
// 覆盖Thread
public void run() {
// TODO Auto-generated method stub
for (int i=0; i < 1000; i++) {
System.out.println("Thread: " + Thread.currentThread().getName() + "_" + i);
// System.out.println(this.getName() + i);
// 上面两个等效
}
super.run();// 如果添加Runnable也会被执行()
}
};
thread3.start();
}
怕有人看不明白,所以咱先讲讲Thread和Runnable。写线程的两中方法:继承Thread类或者实现Runnable接口。
public class Thread extends Object implements Runnable。这就是JDK中的Thread,而接口Runnable就更简单了就一个方法run()
public
interface Runnable {
public abstract void run();
}
所以我最初学习java的时候,就看到过有的文章说“无论是继承Thread还是实现Runnable,最后的start(),调用的都是RUNnable接口的run()”。直接话只能那么的认为,但也是很不准确的。
我再将作者的代码写简单点就是
private static void threadTest3() {
Thread thread3=new Thread(Runnable runnable) {
@Override
// 覆盖Thread
public void run() {
// TODO Auto-generated method stub
for (int i=0; i < 1000; i++) {
System.out.println("Thread: " + Thread.currentThread().getName() + "_" + i);
// System.out.println(this.getName() + i);
// 上面两个等效
}
super.run();// 如果添加Runnable也会被执行()
}
};
thread3.start();
}
此时 thread3.start();,必然是调用 thread3已经重写的run()方法。但是super.run()呢?
很明显是调用父类Thread的run()方法。
据我观察,在jdk里,如果一个类实现了一个接口必然会在这个类里添加这个接口类型的成员变量。Thread中就定义了一个Runnable类型的成员变量target,注意是成员变量,因为它一开始肯定声明是null,接口是引用类型。就好比一个绳子,引用上一个东西和通过绳子用到这个东西是不一定在同一个方法中的。Thread中的做法是这样的:
public
class Thread implements Runnable {
private Runnable target;
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
this.target = target;
}
public void run() {
if (target != null) {
target.run();
}
}
}
可以看出来,Runnable这跟绳子上挂了东西的话,调用super.run(),最终的run()将会是target里实现的run(),也就是上面匿名内部类中定义的方法。
如果Runnable绳子上没挂东西,那就是空方法run().除非子类重载了run().