准确的讲,创建线程只有一种方式,那就是构造Thread类,而实现线程的执行单元(run()方法)有两种方式
方法1:继承Thread类,重写Thread的run方法
方法2:实现Runnable接口的run方法,并把Runnable实例传给Thread类
Oracle官方文档说明:
https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html
第一种(继承Thread类)
public class ThreadStyle extends Thread {
public static void main(String[] args) {
new ThreadStyle().start();
}
@Override
public void run() {
System.out.println("继承Thread方法");
}
}
第二种(实现Runnable接口)
public class RunnableStyle implements Runnable {
public static void main(String[] args) {
new Thread(new RunnableStyle()).start();
}
@Override
public void run() {
System.out.println("实现Runnable接口方法");
}
}
实现Runnable接口和继承Thread类哪种方式更好
- 从代码架构角度:
这里分为两件事情,第一件事情是具体的任务(也就是run()方法里的内容)
第二件事情是跟整个线程生命周期相关的,比如说创建线程、运行线程、销毁线程等,这个是Thread类去做的事情。
这两个事情目的不一样,所以从代码架构角度应该是解耦的,所以实现Runnable接口更好 - 新建线程的损耗:
继承Thread类,每次想新建任务,只能去新建一个独立的线程,而新建独立线程损耗是比较大的;使用Runnable可以使用线程池等工具,利用工具就能减少创建线程、销毁线程带来的损耗。 - 对于扩展性而言,Java不支持双继承
综上所述:实现Runnable接口比继承Thread类更好
两种方法的本质对比
Thread类中run()方法源码
public class Thread implements Runnable {
……
……
此处省略
/* What will be run. */
private Runnable target;
……
/**
* If this thread was constructed using a separate
* <code>Runnable</code> run object, then that
* <code>Runnable</code> object's <code>run</code> method is called;
* otherwise, this method does nothing and returns.
* <p>
* Subclasses of <code>Thread</code> should override this method.
*
* @see #start()
* @see #stop()
* @see #Thread(ThreadGroup, Runnable, String)
*/
@Override
public void run() {
if (target != null) {
target.run();
}
}
...
...
...
}
- 方法1(继承Thread类)run()方法整个都被重写;
- 方法2(实现Runnable接口)传递进来一个target(target就是Runnable对象),判断target不为null,最后调用target.run();
- 本质上两种方法最后都是调用run()方法。
如果同时使用两种方法启动线程?
public class BothRunnableThread {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("我来自Runnable");
}
}) {
@Override
public void run() {
System.out.println("我来自Thread");
}
}.start();
}
}
控制台会打印什么?
运行结果:
我来自Thread
为什么“我来自Runnable”没有输出?
因为new Thread创建了一个匿名内部类,传入了一个Runnable对象,
new Runnable() {
@Override
public void run() {
System.out.println("我来自Runnable");
}
}
之后又重写了run()方法,
@Override
public void run() {
System.out.println("我来自Thread");
}
最后调用start()去运行,
但是重写了run()方法,导致下面3行代码也没了,
if (target != null) {
target.run();
}
所以即便是传入了Runnable对象,它的target.run();也不会执行