前言
网上对实现多线程的方法说法不一,有说1种的,有说2种的,也有3种、4种、6种的.....各种说法不一,不能很好说清楚。为此我查阅了相关文档并从java源码出发写了这篇文章来叙述线程的实现方法到底有多少种。
结论:实现线程的方法实际上只有两种,但是二两种方法的本质实现都是一样的,详看下面的介绍。
Oracle官网所说的实现 两种方法
![](https://i-blog.csdnimg.cn/blog_migrate/ec0bc9264d9ace3739f4757e96eaf2ee.png)
另一种方法是声明实现可运行接口的类。然后,该类实现run方法。然后可以分配类的实例,在创建线程时作为参数传递,然后启动。
- 方法一 实现Runnable接口 的方式
new Thread(()->{
System.out.println("使用Runnable的方式实现线程");
}).start();
- 方法二 继承Thread类的方式
public class Sample{
public static void main(String[] args) {
new Sample().new ThreadSample().start();
}
class ThreadSample extends Thread{
@Override
public void run() {
System.out.println("继承Thread的方式实现线程");
}
}
}
-
两种方法的对比
结论:方法一比方法二好 !
第一:从资源的节约上来看,使用方法二我们如果想新建一个任务,我们只能新建一个独立的线程,而新建一个独立的线程损耗是很大的,需要创建,创建完了执行,执行完了又需要销毁,这样频繁的创建执行销毁对资源的消耗是非常大的。
而如果我们使用Runnable接口的话,我们可以借用线程池之类的工具大大减少创建线程销毁线程所带来的资源消耗,所以从资源的角度方法一更优。
第二:从解耦的角度来看,方法一比方法二更好。
第三:从可扩展性的角度,在java中不支持多继承,当一个类继承了Thread类之后,将无法再继承其他类,所以方法一更优。
两种方法的本质区别
方法一的实现:源码是通过 target.run()
方法二的实现:重写父类的run()方法
Thread类 源码
private Runnable target;
public void run() {
if (this.target != null) {
this.target.run();
}
}
结论:实现线程的方法只有两种,虽然还有线程池之类的其他外在表现,但是我们细追源码,我们会发现都离不开以上两种方式。
而从这两种方法的本质来看:我们从源码中我们可以看到,其实无论是继承Thread类还是实现Runnable接口,他的本质实现都是一样的,都是利用Thread类的run方法,只是继承Thread类是重写run方法,而实现Runnable接口是传进来tanget去调用run方法。