相信很多学习到多线程的小伙伴们都会有一个疑问,实现多线程的方法有几种呢?这种时候我们自然就要去求助度娘啦~
然鹅。。。百度出来的结果五花八门、鱼龙混杂,有的说两种,有的说三种,还有的说四种,对于初学的小伙伴来说可能直接就蒙圈了
那么到底是有几种呢?我们直接去 Oracle 的官网上看看便知道了,附赠上下图链接,小伙伴们也可以自己去看一看哦~
通过 Oracle 官网上的说明我们可以了解到:有两种方法可以创建新的执行线程,一种是将类声明为子类 Thread;另一种方法是声明一个实现 Runnable 接口的类,然后该类实现 run 方法。
接下来就给小伙伴们介绍一下这两种方法~
通过继承Thread类来创建线程
/**
* 实现多线程的方法1:继承Thread类
*/
public class ThreadStyle extends Thread{
public static void main(String[] args) {
ThreadStyle threadStyle = new ThreadStyle();
threadStyle.start();
}
@Override
public void run() {
System.out.println("通过继承Thread类来创建线程");
}
}
通过实现Runnable接口来创建线程
/**
* 实现多线程的方法2:实现Runnable接口
*/
public class RunnableStyle implements Runnable{
public static void main(String[] args) {
RunnableStyle runnableStyle = new RunnableStyle();
Thread thread = new Thread(runnableStyle);
thread.start();
}
@Override
public void run() {
System.out.println("通过实现Runnable接口来创建线程");
}
}
深入源码,探究两种方式的本质
我们先来看一下 Thread 类的 run() 方法
@Override
public void run() {
if (target != null) {
target.run();
}
}
可以看到,当 target 不为空时,运行 target 的 run() 方法,那么 target 又是从哪来的呢?我们继续往下看,找到 Thread 的构造器
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
Thread(Runnable target, AccessControlContext acc) {
init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
}
......
是不是恍然大明白?
- 当我们通过实现 Runnable 接口来创建线程时,调用的是我们传入的 Runnable 对象的 run() 方法
- 而当我们通过继承 Thread 类来创建线程时,我们子类会重写父类的 run() 方法,所以不会执行 target 的判空过程
所以这两种方法的本质对比:
- 通过继承 Thread 类来创建线程:run() 方法被重写了
- 通过实现 Runnable 接口来创建线程:调用 target.run() 方法
火眼金睛,剖析两种方式的区别
到这里相信小伙伴们已经明白了创建多线程的两种方式了,接下来再来一起分析一下这两种方式的区别吧~
通过继承 Thread 类来创建线程的方式:
- 优点:编写简单,如果需要访问当前线程,无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。
- 缺点:
- 在 Java 中,类是单继承的。因为线程类已经继承了 Thread 类,所以不能再继承其他的父类。
- 在本实例中,想要开多个线程,就需要 new 多个 ThreadStyle 对象,资源损耗较大
通过实现 Runnable 接口来创建线程的方式:
- 优点:
- 可以避免 Java 单继承特性而带来的局限,更为的灵活且有利于程序的健壮性。
- 在本实例中,想要开多个线程,只需要 new 一个 RunnableStyle 对象,然后再 new 多个 Thread 类的对象即可,大大节约内存。即适合多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码和数据有效分离(即耦合性降低),较好的体现了 Java 面向对象的设计思想。
- 缺点:编程稍微复杂,如果需要访问当前线程必须使用 Thread.currentThread() 方法。
综上来看,还是推荐通过实现 Runnable 接口这种方式来创建线程