1、为何说只有 1 种实现线程的方法?
目录为什么说本质只有一种实现线程的方式?
实现 Runnable 接口究竟比继承 Thread 类实现线程好在哪里?
实现多线程的多种方式
1、通过实现 Runnable 接口的方式实现多线程
- 首先通过 CustomRunnableThread 类实现 Runnable 接口
- 然后实现了 run() 方法
- 之后只要把这个实现了 run() 方法的实例传到 Thread 类中去就可以实现多线程
.
2、继承 Thread 类
- 与第一种方法不同的是它没有实现接口,而是继承 Thread 类,并重写了其中的 run() 方法
.
3、通过线程池创建线程
- 默认是采用 DefaultThreadFactory
- 它会给我们线程池创建的线程设置一些默认的值,比如它的名字,它是不是守护线程,以及它的优先级
.
4、有返回值的 Callable 也是一种新建线程的方式
- 实现了 Callable 接口,并且给它的泛型设置成 Integer,然后它会返回一个随机数回来
.
5、其他创建方式,
-
定时器 Timer
- TimerTask 实现了 Runnable 接口,Timer 内部有个 TimerThread,它继承自 Thread,因此绕回来还是 Thread
.
.
-
匿名内部类
- 它不是传入一个已经实例好的 Runnable 对象,而是直接用一个匿名内部类的方式把需要传入的 Runnable 给实现出来
.
-
Lambda 表达式
- 匿名内部类和 Lambda 表达式创建线程仅仅是表面层次的,最终它们依然符合最开始所说的那两种实现线程的方式(实现 Runnable 接口或是继承 Thread 类)
.
实现线程本质上只有一种方式
透过现象看本质,以上最终实现线程的方式都是实现 Runnable 接口或是继承 Thread 类,但为什么说这两种方式本质上还是一种呢?
启动线程需要调用 start() 方法,而 start() 方法最终还会调用 run() 方法来执行具体业务功能
实现 Runnable 接口或是继承 Thread 类这两个方式的最主要区别在于 run() 方法的内容来源:
-
方式一:实现 Runnable 接口
- 最终调用 target.run()
.
-
方式二:继承 Thread 类
- run() 整个都被重写,重写之后的 run() 方法直接就是所需要执行的任务,最终还是需要调用 thread.start() 方法来启动线程,而 start() 最终也会调用到这个被重写的 run() 方法,来执行任务
创建线程就只有一种方式:构造 Thread 类
实现线程 "运行内容" 的两种方式:
- 实现 Runnable 接口的 run() 方法,并把 Runnable 实例作为 target 对象,传给 Thread 类,最终调用 target.run()
- 继承 Thread 类,重写 Thread 的 run() 方法,thread.start() 会执行 run()
至于其他实现线程 "运行内容" 的方式(线程池、Timer等)都是对上面 2 种方式的进一步封装
软柠柠吖思考:为什么说本质只有一种实现线程的方式?
答:创建线程就只有一种方式,即构造 Thread 类。但是实现线程的 "运行内容" 却有多种方式,但是都是基于实现 Runnable 接口或者继承 Thread 类,来实现或者重写 run() 方法,最终交由 thread.start() 来执行 run() 方法中的任务。
Runnable 接口与继承 Thread 类对比
实现 Runnable 接口要比继承 Thread 类更好
实现 Runnable 接口的 3 个好处:
- 可以把不同的内容进行解耦,权责分明(从代码架构考虑,实际上,Runnable 接口里面只有一个 run() 方法,它定义了需要执行的内容,这种情况下,实现了 Runnable 与 Thread 的解耦,Thread 负责线程的启动,属性设置等内容,它们权责分明)
- 某些情况下可以提升性能,减少开销(使用继承 Thread 类的方式每次执行一次任务都需要新建一个独立的线程,执行完之后,线程走到生命周期的尽头被销毁。如果还想执行这个任务,就必须再新建一个继承 Thread 类的线程,这个时候如果执行的内容比较少,比如说只是在 run() 方法中简单的打印一行文字,那么它所带来的开销本身并不大。相比于整个线程从创建到执行完毕被销毁这一系列操作,比 run() 方法中打印一行文字本身的开销还要大的多,属实是捡了芝麻,丢了西瓜,得不偿失。如果使用实现 Runnable 接口的方式,则可以把任务直接传入线程池,使用一些固定的线程来完成任务,不需要每次都线程和销毁线程,大大降低了性能开销)
- 继承 Thread 类相当于限制了代码未来的可扩展性(Java 语言本身不支持双继承,如果类一旦继承 Thread 类,后续就无法继承其他的类,这样一来,如果这个类未来需要继承其他类实现功能上的扩展,它就没有办法做到了,限制了代码未来的可扩展性)
总是所述:优先选择通过实现 Runnable 接口的方式来创建线程
标签:Runnable,run,Thread,实现,接口,线程,为何,方法 From: https://www.cnblogs.com/rnny/p/17750841.html