zoukankan      html  css  js  c++  java
  • JAVA-初步认识-第十三章-创建线程的第二种方法-实现Runnable接口

    一. 引言

    现在把之前的示例还原一下,创建线程的第一种方式。(继承创建子类对象,覆盖run方法)

    之前的例子如上,存在着三个线程(目前自己能够理解认识的),主线程和自己创建的两个线程。cpu在这三者之间进行切换。

    现在遇到一个瓶颈,Demo类当中有一部分代码,我们需要用到多线程执行,我们就继承了Thread类(什么时候用多线程)。

    为什么要有多线程的出现,就为为了并发程序,提高效率。类中需要同时运行的代码,我们称之为线程任务,对其进行封装。

    怎么封装呢?线程任务代码必须要在Demo类的,run方法当中。

    一定要写成run()方法么?不一定,封装的代码可以在任何名称的方法里。为了能同时执行部分代码,我们要具备Thread类中的run方法,因此我们要继承Thread类,但是最终要在run()方法调用封装在某一些方法中的并发代码,实现多线程执行。

    这带来的问题就是,想要执行多线程么,继承Thread类,叫爹。但如果Demo类有父类呢?java不允许多继承,怎么来解决这个问题。

    有人提出,Fu类再继承Thread类。这么弄也行,这是不得已而为之。(这样显得体系都是线程体系,线性)

    如果不是线程体系,就不要这么弄,一旦继承了,那么类的所属就确定了。你就属于线程的体系了,你就具备线程里面的所有功能(这里的线程和多线程不是一个东西)。

    当一个类有自己的父类的时候,它就不能继承Thread类了。→讲到这里,相当于又重新开了一个分支,不是按着线性发展的路线来了。

    二.

    代码要并发执行,我们需要多线程来执行。那该怎么办?不继承,我们也必须有其他方案能解决。

    现在就基于下面截图中的例子,来讲解。

    现在的情况就是Demo类继承了Fu类,而且Demo类中还有需要多线程执行的封装代码块show(),但是又不能多继承Thread类,该怎么办?也就是说Demo类需要一个额外的功能,能够将内部的show代码块变成线程任务。以前是通过继承,调用来的,现在没有继承类和方法了。

    现在需要去扩展Demo类的功能,它已经有了爹,再扩展就是接口。是不是我们要实现Demo类的功能扩展?对嘛,那就是接口。

    接口就是用来实现扩展的,一个类在继承一个类的同时,是不是实现更多的接口,实现的目的是为了什么?是为了这个类增加更多的功能。→核心的意思就是,通过实现接口,来增加类的功能,具体怎么实现是各个类自己定义的。

    现在要思考人家有没有给我们提供接口?(以前讲接口的时候,貌似都是自己定义的?)

    如果没提供,我们就要重新想办法(整个思考的流程是这样的,多继承不让用,我们就想通过接口来间接实现,如果连接口都没有,那我们就再想其他办法)。

    现在看到底有没有接口,打开API查阅。

    三. 

    在对Thread类继承过程中,我们重点集中在Thread类中的两个方法上,finalize方法和run方法。

    在对run方法的API查询中,截图如下,

    介绍中交代了,有这么一个接口,叫做runnable。→这种路径找起来是比较方便的,因为我们要做的,是给Demo类增加能封装线程任务的功能。所以,我们要找和任务相关的接口或者方法。

    点一下runable,查阅

    runable本身就是java.lang包中的接口,runable单词含义是可运行的,

    截图中的意思就是,如果你有一个类,想让线程去执行类中的一部分内容,这个类就要实现runable接口。要扩展其功能,让其具备封装任务的能力。

    接下来具体演示怎么,不通过继承,采用接口的形式实现多线程。

    runable接口非常简单,其中的方法只有一个,void run(),这个run就是用来封装线程任务的。

    在Demo类中覆盖run方法,这个run方法来自于,实现runable接口而来。run方法里面的代码就是线程任务。

    现在就已经完成线程任务的封装了。(实现runable接口,覆盖run方法)

    接下来,研究主函数中的内容。询问创建的对象d1是不是线程对象,(说这句话是为了和原继承体系中的知识点进行比较),

    答案:d1不是线程对象。Demo类有自己的父类,有自己的体系,Demo类没有跟Thread类叫爹,它怎么能跟Thread类呢?它根本就不是线程对象(在这里频繁地谈论线程对象,是不是为了讲述实现接口中的线程图解做铺垫呢?以区分于继承体系中的线程?)

    同样的,d1不是线程对象,自然d1.start()也是无效的。是线程才能开启,d1都不是线程对象。这就意味着原有继承体系下的程序已经无法使用了。

    在这里Thread类没有子类来创建对象,形成线程。那就自己出现来形成线程,t1就是线程对象。

    按着这个思路,创建了线程对象,就开始启动线程,运行线程。

    DOS结果显示,没有任何结果。这里线程运行的都是Thread类自己的run方法中的内容,不是我们想要的show方法中的内容,

    它在执行完自己的线程内容后,就结束了。它的run方法做了什么事儿,我不知道,但是可以保证的是,绝对做的不是我们要的show内容。

    我们创建线程,是为了运行我们自己的方法。

    现在的问题就是,创建的t1线程对象和我们Demo类中的run线程任务有什么关系呢?我们现在要让线程对象开启后,调用Demo类中的run方法,这个方法调用一定要具备这个方法所属的对象,(一个方法被执行,通常是被对象所调用,也可以是类名调用,目前只有这两种),这个run方法所属的对象是谁,是Demo。我们将Demo类的对象和Thread类的对象t1联合起来,就有了运行的可能。

    现在就看它俩怎么形成关系。

    四.

    Demo类对象可以调用run方法,它俩怎么构成联系呢?Demo类实现了runable接口。线程类是你要么继承我,覆盖我的run方法,如果你要是有了自己的父类,没办法继承我,你还可以去实现一个接口,是不是这个意思?那就意味着,线程在做的时候,它对外提供了规则。那么你认为,我们是实现规则的,它是不是应该是使用规则的?是吧,笔记本为了扩展功能,对外暴露了USB接口,笔记本是使用接口了,我们做了很多USB的设备是不是在实现接口。

    因此,我们来看一下,我们在查阅Thread类的时候,线程对象它的特点在于,一建立,是不是要有执行的任务?是的,线程没任务,创建它干嘛?在调用start()之前,线程就要有任务。

    以上面的截图来看,我们在t1.start()之前就要有任务,应该在Thread线程对象构造的时候,赋予任务。

    线程对象一创建就应该有任务,然后我们开始调用start()开启。没任务,就晚了。

    在Thread类的API介绍中,除了有空参数的构造函数,还有runable接口的构造函数。这就意味着,线程对象一建立,就有了runable接口对象进来。

    而runable接口对象里面,就是封装的线程任务,

    因此,直接将d传递到Thread类的构造函数中,(Demo类实现了接口,它的对象怎么就是接口对象了?)

    视频中说d是runable的子类对象,

    截图中说“其run方法被调用的对象”,在下面的截图中,run方法被调用,就是Demo类。

    最后整个程序经过编译,运行是没有问题的。

    上面所说的就是线程创建的,第二种方式。这里面包含了很多步骤。

    针对第三点,也就是说你不传递,线程走的是自己的run方法,你传递,就走你传递的那个。

    →依照视频中的讲解来看,实现runable接口的Demo类对象,具备了可以执行的线程任务,但是自己是开启不了的。

    因此,通过创建线程对象,在创建的过程中,将Demo类对象传递给线程对象,其实传递的是封装的run方法。

  • 相关阅读:
    linux权限补充:rwt rwT rws rwS 特殊权限
    关于Linux操作系统下文件特殊权限的解释
    Java学习笔记——Java程序运行超时后退出或进行其他操作的实现
    Java实现 蓝桥杯 算法提高 判断名次
    Java实现 蓝桥杯 算法提高 判断名次
    Java实现 蓝桥杯 算法提高 日期计算
    Java实现 蓝桥杯 算法提高 日期计算
    Java实现 蓝桥杯 算法提高 概率计算
    Java实现 蓝桥杯 算法提高 概率计算
    Java实现 蓝桥杯 算法提高 复数四则运算
  • 原文地址:https://www.cnblogs.com/wsw-bk/p/8022047.html
Copyright © 2011-2022 走看看