上面两张图片来自于jdk官方文档。
两种方式的对比
- 实现Runnable接口更好
- 实现Runnable接口方式中,线程的新建和线程具体执行的任务(run方法)是解耦的。
- 继承Thread类新建一个任务只能通过新建一个独立的线程,资源消耗大;实现Runnable接口可以利用已存在的线程(线程池等),提交不同的Runnable实现类来实现不同的任务。
- Java支持单继承,多实现。
-
本质对比
- Runnable接口:Thread类run方法调用传入的Runnable实现类的run方法
- 直接对Thread类的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();
}
}
由于实现Runnable接口是通过Thread的run方法调用Runnable实现类的run方法,而继承Thread类会将Thread类本身的run方法重写,导致Thread类无法调用到Runnable的run方法,所以只有重写的run方法会生效。
总结:
通常讲实现多线程的方式有两类(官方文档):实现Runnable接口;继承Thread类
精准的讲,创建线程只有一种方式,就是构造Thread类,而实现线程的执行单元有两种方式
- 方式一:实现Runnable接口的run方法,并把Runnable实例传给Thread类
- 方式二:重写Thread的run方法(继承Thread类)
多线程的实现方式,在代码中写法千变万化,但是本质不变,都是这两种方式。
面试题:
- 有多少种实现线程的方法
- 从不同角度看,会有不同的答案
- 典型的答案是两种
- 看原理,两种的本质是一样的。
- 其他方式如计时器,线程池,FutureTask等都是使用的这两种方式实现的。
- 结论
- 实现Runnable接口与继承Thread类那种方式更好:Runnable接口
- 解耦
- 新建线程的损耗
- 单继承