首页 > 其他分享 >1、为何说只有 1 种实现线程的方法?

1、为何说只有 1 种实现线程的方法?

时间:2023-10-09 10:12:03浏览次数:36  
标签:Runnable run Thread 实现 接口 线程 为何 方法

1、为何说只有 1 种实现线程的方法?

为什么说本质只有一种实现线程的方式?

实现 Runnable 接口究竟比继承 Thread 类实现线程好在哪里?

目录

实现多线程的多种方式

1、通过实现 Runnable 接口的方式实现多线程

  • 首先通过 CustomRunnableThread 类实现 Runnable 接口
  • 然后实现了 run() 方法
  • 之后只要把这个实现了 run() 方法的实例传到 Thread 类中去就可以实现多线程

image-20231008213424779.

2、继承 Thread 类

  • 与第一种方法不同的是它没有实现接口,而是继承 Thread 类,并重写了其中的 run() 方法

image-20231008213654053.

3、通过线程池创建线程

  • 默认是采用 DefaultThreadFactory
  • 它会给我们线程池创建的线程设置一些默认的值,比如它的名字,它是不是守护线程,以及它的优先级

image-20231008214811236.

4、有返回值的 Callable 也是一种新建线程的方式

  • 实现了 Callable 接口,并且给它的泛型设置成 Integer,然后它会返回一个随机数回来

image-20231008215906888.

5、其他创建方式,

  1. 定时器 Timer

    • TimerTask 实现了 Runnable 接口,Timer 内部有个 TimerThread,它继承自 Thread,因此绕回来还是 Thread

    image-20231008220500658.

    image-20231008220535897.

  2. 匿名内部类

    • 它不是传入一个已经实例好的 Runnable 对象,而是直接用一个匿名内部类的方式把需要传入的 Runnable 给实现出来

    image-20231008221713029.

  3. Lambda 表达式

    • 匿名内部类和 Lambda 表达式创建线程仅仅是表面层次的,最终它们依然符合最开始所说的那两种实现线程的方式(实现 Runnable 接口或是继承 Thread 类)

    image-20231008221742589.

实现线程本质上只有一种方式

透过现象看本质,以上最终实现线程的方式都是实现 Runnable 接口或是继承 Thread 类,但为什么说这两种方式本质上还是一种呢?

启动线程需要调用 start() 方法,而 start() 方法最终还会调用 run() 方法来执行具体业务功能

实现 Runnable 接口或是继承 Thread 类这两个方式的最主要区别在于 run() 方法的内容来源:

  • 方式一:实现 Runnable 接口

    • 最终调用 target.run()

    image-20231009081030550.

  • 方式二:继承 Thread 类

    • run() 整个都被重写,重写之后的 run() 方法直接就是所需要执行的任务,最终还是需要调用 thread.start() 方法来启动线程,而 start() 最终也会调用到这个被重写的 run() 方法,来执行任务

创建线程就只有一种方式:构造 Thread 类

实现线程 "运行内容" 的两种方式

  1. 实现 Runnable 接口的 run() 方法,并把 Runnable 实例作为 target 对象,传给 Thread 类,最终调用 target.run()
  2. 继承 Thread 类,重写 Thread 的 run() 方法,thread.start() 会执行 run()

至于其他实现线程 "运行内容" 的方式(线程池、Timer等)都是对上面 2 种方式的进一步封装

软柠柠吖思考:为什么说本质只有一种实现线程的方式?

答:创建线程就只有一种方式,即构造 Thread 类。但是实现线程的 "运行内容" 却有多种方式,但是都是基于实现 Runnable 接口或者继承 Thread 类,来实现或者重写 run() 方法,最终交由 thread.start() 来执行 run() 方法中的任务。

Runnable 接口与继承 Thread 类对比

实现 Runnable 接口要比继承 Thread 类更好

实现 Runnable 接口的 3 个好处:

  1. 可以把不同的内容进行解耦,权责分明(从代码架构考虑,实际上,Runnable 接口里面只有一个 run() 方法,它定义了需要执行的内容,这种情况下,实现了 Runnable 与 Thread 的解耦,Thread 负责线程的启动,属性设置等内容,它们权责分明)
  2. 某些情况下可以提升性能,减少开销(使用继承 Thread 类的方式每次执行一次任务都需要新建一个独立的线程,执行完之后,线程走到生命周期的尽头被销毁。如果还想执行这个任务,就必须再新建一个继承 Thread 类的线程,这个时候如果执行的内容比较少,比如说只是在 run() 方法中简单的打印一行文字,那么它所带来的开销本身并不大。相比于整个线程从创建到执行完毕被销毁这一系列操作,比 run() 方法中打印一行文字本身的开销还要大的多,属实是捡了芝麻,丢了西瓜,得不偿失。如果使用实现 Runnable 接口的方式,则可以把任务直接传入线程池,使用一些固定的线程来完成任务,不需要每次都线程和销毁线程,大大降低了性能开销
  3. 继承 Thread 类相当于限制了代码未来的可扩展性(Java 语言本身不支持双继承,如果类一旦继承 Thread 类,后续就无法继承其他的类,这样一来,如果这个类未来需要继承其他类实现功能上的扩展,它就没有办法做到了,限制了代码未来的可扩展性)

总是所述:优先选择通过实现 Runnable 接口的方式来创建线程

标签:Runnable,run,Thread,实现,接口,线程,为何,方法
From: https://www.cnblogs.com/rnny/p/17750841.html

相关文章

  • js数组转字符串方法(转)
    JavaScript 允许数组与字符串之间相互转换。其中Array 方法对象定义了3 个方法,可以把数组转换为字符串,如表所示。数组方法说明toString()将数组转换成一个字符串toLocalString()把数组转换成本地约定的字符串join()将数组元素连接起来以构建一个字符串......
  • 树结构操作通用方法
    /***树操作通用方法,将一些常用方法提炼出来,方便使用。*@module树操作工具*/import{cloneDeep}from'lodash';import{uniqueArray,arrayRemoveAll,arrayRemove}from'./index';/***将数据转换成tree所需格式*@param{object}data要进行转换的object......
  • android 代码禁用某个应用的方法
    注意需要android.uid.system权限设置包可用+PackageManagerpm=getPackageManager();+pm.setApplicationEnabledSetting(this.getPackageName(),PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,0);设置包不可用+pm.setApplicationEnabledSettin......
  • IEDA 中Maven 编译错误 Compilation failure的解决方法
    IEDA中Maven提示编译错误Compilationfailure 检查发现项目虽然已经配置了JDK11,但是却引用的是JRE1.5解决方法:1、修改maven的setting.xml文件中添加下面的配置: <profile> <id>jdk-11</id> <activation> <activeByDefault>true</activeByDefault> <jdk>......
  • 万字长文详解Java线程池面试题
    王有志,一个分享硬核Java技术的互金摸鱼侠加入Java人的提桶跑路群:共同富裕的Java人今天是《面霸的自我修养》第6篇文章,我们一起来看看面试中会问到哪些关于线程池的问题吧。数据来源:大部分来自于各机构(Java之父,Java继父,某灵,某泡,某客)以及各博主整理文档;小部分来自于......
  • 设置了.gitignore文件不起作用,解决方法
    如果按照正确设置了.gitignore文件,但仍然存在问题,可能是由于以下原因:文件已经被Git跟踪:如果在设置.gitignore之前,文件已经被Git跟踪并提交过一次,那么.gitignore对这个文件将不起作用。需要先使用以下命令将文件从Git仓库中移除:gitrm--cached<file>然后再重新提交一次。......
  • 绑定方法和非绑定方法隐藏属性和property装饰器 绑定方法
    绑定方法和非绑定方法隐藏属性和property装饰器绑定方法类中得方法类能来调用,对象也能来调用,就看该方法绑定给谁了,绑定给谁就有谁来调用classStudent():hero_work='射手'def__init__(self,name,speed,hp,atk):self.name=nameself.speed=speed......
  • 多线程,线程同步(synchronized),并发问题
    多个线程同时操作一个对象,就会出现并发问题,所以需要线程同步,线程同步是一种等待机制。 线程同步的形成条件:队列+锁(锁就是例如上厕所,一个进去锁住避免其他进入。到下一个进去再锁住)线程同步来解决线程的不安全性弊端!: ......
  • 类的绑定方法和隐藏属性
    1.绑定方法定义:定义完类之后,可以在类里面写一些方法,在类的外部直接调用类内部的方法不能调用那么,类中得方法到底是使用类调用还是使用对象来调用?类中得方法类能来调用,对象也能来调用,就看该方法绑定给谁了,绑定给谁就有谁来调用#对象的绑定方法:classStudent():schoo......
  • 多线程,守护线程daemon
    简介: 下面例子:首先两个线程类实现Runnable接口 然后在主线程模拟一下上帝守护你 其中,setDaemon方法可以切换线程模式......