创建多线程方式:继承 Thread 类 和 实现 Runnable 接口
JDK 中已提供了对多线程的支持,可以很方便 实现多线程编程,主要有两种方式:一种是继承 Thread 类,另一种是实现 Runnable 接口。
继承 Thread 类
先查看 Thread 类源码,了解其结构:public class Thread implements Runnable { … }。
Thread 类实现了 Runnable 接口,它们之前具有多态关系。使用继承 Thread 不支持多继承;若要支持多继承,可以使用实现 Runnable 接口的方式,这两种创建线程的方式在工作时性质是一样的,没有本质区别。
通过继承 Thread 类来使用线程:
- 继承 Thread 类。
- 重写 run 方法。
- 在 run 方法里面写任务代码。
- 创建线程对象。
- 调线程对象和 start() 方法开启线程,内部会 自动执行 run() 方法。
1 | public class RunThread { |
输出:
1 | 运行结束! |
结果中,run() 方法里的执行的时间较 main 线程更晚,意味着使用多线程时,代码的运行结果顺序与代码执行顺序或调用顺序无关,并且执行 start() 方法的顺序不代表线程启动的顺序。线程是个子任务,由 CPU 以不确定的方式,或者说随机的访问调用线程中的 run 方法。
实现 Runnable 接口
查看 Thread 类的构造方法,有两个构造方法可以传入 Runnable 接口对象。
- 定义 Runnable 接口的实现。
- 重写 run 方法。
- 在run方法中写任务代码。
- 创建 Runnable 接口对象。
- 创建 Thread 对象, 传入 Runnable 接口对象。
- 调用 start() 开启新线程, 内部会自动调用 Runnable 的run()方法。
1 | public class RunRunnableImpl { |
从 Thread 构造方法 public Thread(Runnable target) 可以看出,其除了传入 Runnable 接口对象,还可以传入一个 Thread 对象,这样完全可以将一个 Thread 对象中的 run() 方法交由其它的线程调用。
查看 Thread 原码可以了解到:
- Thread 类的构造方法,传递了 Runnable 接口对象。
- 通过 init() 方法找到传递的 target 给成员变量的 target 赋值。
- 查看 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/