创建多线程方式:继承 Thread 类 和 实现 Runnable 接口

  JDK 中已提供了对多线程的支持,可以很方便 实现多线程编程,主要有两种方式:一种是继承 Thread 类,另一种是实现 Runnable 接口。

继承 Thread 类

先查看 Thread 类源码,了解其结构:public class Thread implements Runnable { … }。

Thread 类实现了 Runnable 接口,它们之前具有多态关系。使用继承 Thread 不支持多继承;若要支持多继承,可以使用实现 Runnable 接口的方式,这两种创建线程的方式在工作时性质是一样的,没有本质区别。

通过继承 Thread 类来使用线程:

  1. 继承 Thread 类。
  2. 重写 run 方法。
  3. 在 run 方法里面写任务代码。
  4. 创建线程对象。
  5. 调线程对象和 start() 方法开启线程,内部会 自动执行 run() 方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class RunThread {
public static void main(String[] args) {
// 4.创建 Thread 类的子类对象
MyThread mt = new MyThread();
// 5.调用start()方法开启新线程,系统默认调用run方法
mt.start();

System.out.println("运行结束!");
}
}

/**
* 创建新执行线程方法一:
* 1.继承Thread类
* 2.重写run方法
* 3.将要执行的代码写在run方法中
*/
class MyThread extends Thread {
public void run() {
System.out.println("This is MyThread2 ");

}
}

输出:

1
2
运行结束!
This is MyThread

结果中,run() 方法里的执行的时间较 main 线程更晚,意味着使用多线程时,代码的运行结果顺序与代码执行顺序或调用顺序无关,并且执行 start() 方法的顺序不代表线程启动的顺序。线程是个子任务,由 CPU 以不确定的方式,或者说随机的访问调用线程中的 run 方法。

实现 Runnable 接口

查看 Thread 类的构造方法,有两个构造方法可以传入 Runnable 接口对象。

  1. 定义 Runnable 接口的实现。
  2. 重写 run 方法。
  3. 在run方法中写任务代码。
  4. 创建 Runnable 接口对象。
  5. 创建 Thread 对象, 传入 Runnable 接口对象。
  6. 调用 start() 开启新线程, 内部会自动调用 Runnable 的run()方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class RunRunnableImpl {
public static void main(String[] args) {
// 4.创建 Runnable 接口对象
MyRunnable mr = new MyRunnable();
// 5.将其当作参数传递给Thread的构造函数
Thread thread = new Thread(mr);
// 6.开启线程
thread.start();

System.out.println("main 运行结束");
}
}

/**
* 1.定义一个类实现Runnable接口
* 2.重写run方法
* 3.多线程执行代码写在run()方法里面
* 4.调用 start() 方法
*/
class MyRunnable implements Runnable {

@Override
// 2.重写run方法
public void run() {
System.out.println("This is MyRunnable!");
}
}

从 Thread 构造方法 public Thread(Runnable target) 可以看出,其除了传入 Runnable 接口对象,还可以传入一个 Thread 对象,这样完全可以将一个 Thread 对象中的 run() 方法交由其它的线程调用。

查看 Thread 原码可以了解到:

  1. Thread 类的构造方法,传递了 Runnable 接口对象。
  2. 通过 init() 方法找到传递的 target 给成员变量的 target 赋值。
  3. 查看 run 方法,发现 run 方法中有判断,如果 target 不为 null 就会调用 Runnable 接口对象的 run 方法。

两种实现方式区别

查看源码的区别:

  • 继承 Thread:由于子类重写了 Thread 类的 run(), 当调用 start() 时, 直接找子类的 run() 方法。
  • 实现 Runnable: 构造函数中传入了 Runnable 接口对象, 成员变量记住了它, start() 调用 run() 方法时内部判断成员变量 Runnable 接口对象是否为空,不为空编译时看的是 Runnable 的 run() ,运行时执行的是实现类的 run() 方法

继承 Thread:

  • 好处是:可以直接使用 Thread 类中的方法,代码简单。
  • 弊端是:如果已经有了父类,就不能用这种方法。

实现Runnable接口:

  • 好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,而且接口是可以多实现的。
  • 弊端是:不能直接使用 Thread 中的方法需要先获取到线程对象后,才能得到 Thread 的方法,代码略有复杂。

创建多线程方式:继承 Thread 类 和 实现 Runnable 接口

http://blog.gxitsky.com/2019/05/19/Java-Thread-03-create-multi-thread/

作者

光星

发布于

2019-05-19

更新于

2022-06-17

许可协议

评论