00:00
好,那么关于线程的第一种方式呢,咱们就讲清楚了,然后呢,接着咱们来看。刚才呢,咱们写的这个题目呢,用的是第一种方式实现的,然后这里边儿呢,我们会发现呢,咱们使用的是继承的方式。那么继承呢,咱们都知道在Java当中呢,是叫单继承的,那原IG呢,就是我们现在呢,让这个print number呢,继承了thread之后,如果说这个类呢,还想有一个,诶继承的关系啊,想拓展一些功能,那不好意思了,他就不能够再继承其他的类了。啊,一定程度上呢,会有这个局限性啊,那怎么办呢?那这是我们再看看第二种方式,诶打开我们这个API啊好,那我们往下找。诶,看到这儿啊,说the other way to,说第二种方式怎么着呢,说创建一个线程,让它呢,声明是。一个类啊,让这个类呢,实现runable的接口。所以这种方式呢,我们就称为那叫实现runable接口的方式了。好,那么实现这个接口的话呢,自然而然的,你要把这个接口中的抽样方法呢去重写,或者要实现一下这个reable里边呢,就只有一个run方法。
01:05
它也叫run,所以呢,我们就需要呢,去实现这个run方法,这是算第二步,接下来说呢,当前这个类的一个实例啊,创建了,然后呢分配,分配就创建的意思,然后呢作为一个参数传递到我们。啊,创建TH的这个实例的时候的这个啊,参数里边说白了就是放到S构造器里边。然后接着呢去start啊,这块说的稍微的有点模糊啊,那我们直接看这个实例了。说这个实例的话呢,是做同样的事儿,也就是说呢,仍仍然呢,是计算一下比指定这个数大的这个质数有哪些这样的一个需求,首先。生命一个类去实现这个接口。诶然后呢,这呢是通过构造器的方式呢,比指定那个数大,所以这块呢有一个属性啊,诶你通过构造器呢去赋值就行了,然后呢,诶软方法里边呢,就是你要计算比指定那个数大的这个质数都有哪些的这个逻辑。这第二步第三步的话呢,创建一个你这个实现类的对象。
02:04
然后呢,把这个对象啊,作为参数传递到我们瑞的这个类的构造器当中。那显然呢,他就有这样的过道器,然后呢,接下来你造了一个呃,现成的对象了,然后呢,接着还是去调start这个方法了。这呢,就是我们说的第二种方式。好,这个说完以后呢,我们回过来,回到我们这个代码这个层面啊,首先咱们先把这个步骤呢,先捋一下啊,把这种方式呢,首先我们称为呢叫实现。哎,Able接口的方式跟上面这个继承的方式呢,不一样了,第一步。啊,需要呢,去创建一个。啊,实现。叫able接口的类是吧。接口的这个类啊,这个我们就称为它叫实现类了,然后第二步呢。哎,需要呢,你去实现我们这个接口里边这个出版方法。
03:02
这个实现呢,你要觉得跟上面这个实现老出现,你就用继承呃重写是吧,呃,其实这个严格上来讲的话呢,就要实现这个词好一点啊,就凡是对于抽象方法的一个重写的,咱们都要实现啊。实现。接口中的。哎,Run方法,然后呢,同样的啊,咱们上边这个run方法做什么事儿,这个呢也做什么事,也就是说呢,你这个线程到底要做什么操作,把它呢,写在我们这个run方法这个方法体里边,然后第三步。哎,创建。哎,当前实现类的对象。啊,这算第三步了,然后第四步。说,将此对象作为参数。传递到。哎,传递到是不是我们这个re的这个构造系统是吧。哎,构造器中,然后呢,我们去创建TH的这个类的实例。
04:01
哎,所以我们new的呢,是一个thread啊。然后呢,我们造完这个对象之后呢,第五步。那就是通过我们类的这个实例是吧。调用咱们这个四大的方法。OK啊,这呢,就是我们说的这个步骤,这个star方法呢,跟咱们上面这个star是一个方法不。想想。大的方法。对,都是咱们thread类的那个四大方法是吧,所以说都是一个啊,也就是说它这个作用呢,也是一样的。好,这呢是我们写的这样的几个步骤,然后呢,咱们把刚才呢写的这个题目呢,用这个实现randomable接口的这种方式呢,我们再来做一遍,OK啊好,把这个呢,我们CTRLC一下这个咱们就在randomable这里边啊,去右键啊新建一个class。这个呢,我们还是呢叫呃,Even。哎,Number的一个测试啊,就它。好这呢,我们刚才提到了有这样的几个步骤啊,我就先比如写到这儿了啊,然后首先的话呢,我们做的是这个事儿。
05:04
哎,比如说我们就把它写到这儿了啊,现在我们就声明一个class。啊,这呢,我们比如说就是一个叫,嗯。这个。哎,它的一个printer是吧,让他呢去implement一下,这个叫random。哎,这么着。哎,这样啊。好,然后呢,接下来我们这个renoable这个接口里边呢,它有一个抽象的叫run方法,那自然呢,我们就需要呢去实现这个方法了,CTRL挨一下。诶把这个方法呢,我们点一下,哎这呢就是第二步。哎,把它拿拿过来。好,那么我们这个县城要走什么事呢?咱们要便利啊,100以内的偶数啊,跟我们刚才另外的这种继承的方式呢,做的事是一样的啊,For。I呢从一开始I呢,小于等于100。哎,佳佳。好在这里边我们直接呢打印这个I,那为了方便我们去查看一下这个线程啊,所以我这块调一个方法,点current get一个name。
06:06
然后呢,冒号一下,哎,就这么着。好了,那么这个事儿呢,我们就做完了,然后第三个事儿呢,叫创建当前实现类的对象,这个呢,我们就放在咱们下边这个main方法啊,测试里边呢去做。首先创建这个类的对象。啊,这个我们比如说叫个P了,哎,你有一个他。哎,这就可以了,好,那么第二步呢,需要呢,创建thread类的一个对象。那这时候我们就需要去new一个thread。哎,有一个thad,好,那么在这个位置呢,我们CTRLP一下,在当前这个TH里边,这构造器当中,它有一个参数呢,叫做randomable啊,那我们刚才是提供了个random的实现类的一个对象了,那这呢相当于是以多态的方式,我们把这个P呢就传进来了。没问题是吧,这是多肽吧。啊,这个咱们前两天不是这个晚上考试了啊。
07:03
嗯,我听这个有兰老师说,说这个很多同学在连多肽是啥,现在还没整明白呢,这就有点过分了哈。啊,这个呢,这不就多态的体现了啊,凡是其实你看到凡是你这块呢,右边new的这个对象这个类型,这不构造器吗?跟你左边生命这个类型,它俩只要不一样。而且还没报错是吧。那就一定是多肽吧?对,其实非常好识别啊,这个得得清楚。好,那么接下来呢,我们就用了一个thread。啊,这个我们叫体。没问题,好,这是我们的这一步,然后最后一步。哎,调用这个四大的方法。哎,这么着,所以呢,这个T一点叫start,诶这不就可以了吗。这呢,就是我们说的这样的几个步骤,行来我们做一个。那这就出来了,你看这呢,它写的不是may啊,写的是S杠零,说明我们就是这样的一个分线程,那么也可以呢,把这个逻辑操作CTRLC一下,咱们再写到这个位置。
08:02
啊,那么这个位置的代码呢,咱们知道了,这实际上是我们这个主线程是吧,哎每方法哎对应的。这个主线程啊,执行的这个操作。啊,OK,好,那么这是我们再去做一个。那这时候你看到这个may,这就我们下边的这个主线程做的这个事儿,然后呢,12杠零,就我们创这个分线程做这个事儿。啊,就可以了。好,这呢,就是我们说的这样的一道问题。那这个写完之后的话呢,我们也再创建一个分线程啊,比如我写到写哪儿其实都行啊,比如你要写到这儿这呢,我们增加了一个拓展的需求。说呢,在。创建一个线程。哎,说呢用于便利啊,100以内的偶数,那么这时候我们看看这个时候咋做呢。呃,首先的话呢,我们不能说还用这个,呃,T去start了,咱们刚才讲继承的时候也说了,只能是start一次是吧?啊,那么往上推的话呢,是我们得再去new一个了。
09:05
好,那么你ad传个P。那这个P的话呢,还需要再去创建一个。其实不用。是吧,啊,因为这块呢,我们说呢,你要是在创建一个线程,这个线程其实体现为就是一个thad的一个对象了,所以主要呢是造的它这个呢,其实就看到是一个数据了,把这个数据呢传递过去而已,这个数据呢,实际上可以共用是吧。哎,就可以,所以呢,我们从这一步开始呢,做一个重新的操作啊,这个叫T2,然后呢,诶T2呢,去调一个大的这个方法。诶应该是,诶应该是这样子的一个情况了。来,我们再去做一个run。那这就可以了啊,这个因为咱们写的比较靠后,所以他这块执行呢,它就显得就比较靠后了。啊,别人都执行完了啊,诶就大家最后执行了,这个呢,12杠一这我们也能看到了,这就是一个新的线程没问题,行这个呢,你在便利的次数多一点,这个能看到他们可能会有个交互的情况了,啊行这块呢,它就相对要靠后一些,但是代码呢没问题。
10:05
这呢,就是我们讲的第二种方式。那就说完了,体会一下。好,那么这种方式完了以后呢,针对于咱们刚才写的这个题目,不是做了一个课后练习题吗。一个线程做这个事儿,另外一个线程做这个事儿,咱们呢讲了两种方式,第一种方式呢,就是我们实打实的去提供两个继承的这种方式的啊,这两个子类了,然后第二种呢,咱们写成种匿名上了。那么问大家能不能也类似于这种匿名的这种方式呢?咱们写个方式三呢?方式三这个一下子要求的就比较高了哈,我呢也不去明显的去写一个类去实现这个接口了。我直接呢,就是写匿名的了。啊,这块你得捋啊,怎么着呢,首先呢,咱们大方向来讲呢,New的是thread是吧。还是ad啊,然后呢,Start呢,是不是还是那个。
11:00
也没问题,只不过呢,原来的时候呢,我们是继承所在类在这个位置。咱们是加的大括号里边的写的RA是吧,这个称为呢,叫继承类的这个子类的对象了,那现在呢。对,现在呢,是不是在这个小括号里边提供一个renoable的实现类的对象是吧。怎么着?你一个。Re。然后小括号大括号,然后在这儿。重启乱方法。是不是这么着了?啊,这个呢,就看大家这个是不是对代码一下子能够反应过来啊,然后这块呢,是我们打印这个叫偶数的。那就这样。然后再来一个啊,再写一遍啊,New一个thread。然后呢,调大的方法,我们第二种实现方式呢,就是new thread。所以呢,哎,我们就是这样写,然后呢,在小括号里边呢,传一个renoable的一个接口的实现类的对象,那这块我们是匿名的吗。
12:04
啊,Able小括号,然后这个大括号呢,我们去重写这个方法。其实就是一个软方法呗。哎,CTRLC粘过来这个呢,比如说是奇数,那就这样就行。这个呢,相当于就是我们这个实现的方式啊。哎,使用。来实现。接口的。这个方式来做的啊,只不过这个呢,我们相当于是提供了。Able接口。哎,Re,这个接口叫匿名实现类的匿名对象是吧,把这个对象呢,直接呢,附到我们的这个位置了。哎,这就是这个匿名实现类的匿名对象OK。好,这时候我们再去做一个run。你看也是没问题的啊。哎,稍微的大家去体会体会这个事儿行,那这个题目呢,我们就写完了,写完以后的话呢,那么回到我们刚才提到这个创建方式这块,两种方式咱们就说完了。
13:02
说完以后呢,下边我们做一个对比啊。所以一个呢叫继承。啊,就我们对应的是这个集成的这个步骤,那一个呢,叫做实现。啊,这两种方式呢,我们往这儿摆一下。来听一下啊。我们盖一盖啊好这两种方式了,问这两种方式的话呢,对比一下。有没有好坏之说?或者倾向于写哪个?现在写re,是吧?为啥呢?这你看这有五部,这有四部。人机一个。嗯。啊,继承只能单继承这个可以多实现是吧,对这是一个明显的好处哈,行,那咱们呢,就从这几个角度呢来说一说,首先第一个呢,这俩你看有没有什么共同点。
14:00
都要重写run方法,这算是共同点吗?呃,也算,但是呢,你这个run你注意啊,写的不是。覆盖的同一个啊,这个覆盖的是thread里边这个是吧,这个覆盖的是。A reable里边的RA,所以呢,这不是同一个run,甚至咱就别算是共同点了。再往下看。对,咱们最后呢,启动这个线程用的都是star方法,是同一个大吗?是的,都是咱们thread这个里边的start是吧?哎,那也就意味着啊,这边我写一个第一个点就是要想启动线程,是不是都得是调用thread类的run方法是吧。这个启动线程。使用的都是。哎,这个类中。定义的。四大的方法。这个呢是一个共同点,呃,那么另外呢,我还想再写一个共同点哈,就是你看不管是咱们所说的这个第一种继承的方式也好,第二种叫实践的方式也好,你发现呢,咱们其实new的呀,我说呀,其实都是surprise的对象。
15:02
只不过第一个呢,是你爱的子类的对象。第二呢是thread,就是它这个类的对象了。其实呢,都可以算成是wad的对象是吧,说白了就是你这时候所谓的线程,线程就是外ad是吧。啊,只不过第二种方式呢,我们是套了一个这个实现啊,所以说呢,我们创建的这个线程啊。对象。这个都是啊,Thread。类啊,霍奇。子类的这个对象。啊之类的,或者叫实力也行啊,说白了就都是跟thad是相关的。哎,这儿呢,我们看的是他们的这个共同点啊。好,那么不同点的话呢,当然呢很明显,一个呢是继承的方式,一个呢是实现的方式,这呢就算是这个不同点了。啊,这个补充点我在这写一下啊,就是就是一个呢是类的继承啊,一个呢是接口的实现。
16:00
啊,这呢算是两种不同方式,那基于这两种不同方式呢,我们其实有一个建议哈,就是推荐的写哪个呢。啊,建议使用实现able接口的方式。是吧,那既然有这样的建议呢,那肯定你要说清楚这种方式的好处是什么,其实也间接的就说明他俩的不同点了。啊,这个我们说一下啊re,这个方式的好处。哎,这个怎么说呀。对第一个点的话呢,大家提到了,就是我们使用实现的方式啊,相当于是避免了这个继承性的这种局限性是吧。啊,实现的这个方式。嗯,避免了。类的单继承的局限性。诶,这个是没问题的。好,这呢也是我们比较明显的能够看到的一个点啊,那其实这块呢,还有其他的好处,只不过呢,大家呢,可能再去看呢,就不会特别的明显啊,我这块呢,我来说一下啊,你看我们讲这个实现的这种方式的时候呢,这块呢,我们再创建了一个线程,让这个线程呢,同样是便利100以内的这个偶数,这个时候呢,你会发现呢,我们并没有呢,再去创建一个这个实现类的对象。
17:16
啊,就这块儿呢,两个线程没问题,但是我们用的是同一个P是吧。啊,这是OK的行,那么这个P的话呢,我能不能就把它理解成是我们这两个线程的共享数据呢。因为大家共用一个这个是吧。好,那我再换句话说啊,这儿呢是我们实现这个接口,这里边儿呢,假设咱们后续呢,会有这样的这个场景了,假设我这块呢定一个啊,比如呢是一个搭布型的,咱们以后会有真实的例题,假设是money。就1000块钱啊,那么我说呢,现在这两个县城呢,其实共用的是这一个1000块钱。因为你供应的是同一个这个P。这个P呢,就是唯一的一个对象,这个对象呢,是不是就只有这一份。好,那么同样的,我要是把这个变量呢,我CTRLC,我复制到咱们继承的这个方式里边,我放到这个位置。
18:02
那么我们此时的这两个线程共用的是同一个吗?你会发现呢,不是了,因为呢,我们下边呢,是不是创建了两个这个类的对象。那因为呢,你这是一个实例变量了,所以呢,就相当于每一个对象有一份了,那同学说那我们就加上static,那当然了,加上static肯定多个线程就共用一个了。当然呢,你不就是加了斯里克了吗?毕竟有点区别的是吧,诶所以这块我就先把它注入掉啊,那G什么意思呢,就是如果说我们多个线程,后续呢,我们要讲。这个对,处理这种共享数据问题了,假设呢,我们现在有三个窗口呢,去买买票卖票啊,那么一共呢,假设呢,就卖100张票,现在这100张票呢,就是三个线上的共享数据了。那么如果你要有共享数据的话呢,我们说用这种实现的方式呢,就会更方便一些。因为呢,你天然的话呢,它就有这种共享之处是吧。
19:00
哎,这块结论上这块有点。整不动了是吧,因为啥呢?诶我们这块呢,造一个reable实现类的对象,我把这唯一的一个对象呢,作为一个参数传递到多个线程当中,那你这个对象呢,天然的不就是共享吗。你不用静态都你都是共享的是吧,但是你要记得的方式的话呢,要想体验共享,你必须得静态化。那也就是说呢,咱们对于有共享数据的问题的话呢,用实现的这种方式呢,会更方便一些,因为呢,它不就体现就是天然的,它就有这种共享的说法吗。OK,但并不是说继承性做不了啊,也能做,只是没有它呢更方便一些啊,所以这块呢,我们说叫更适合来处理有呃共享数据的问题。哎,多个线程有共享数据了,我们用实现方式呢,比较方便。OK,这呢是两个优点,这块呢,其实我们还可以呢,再去写一个优点,这个优点呢。啊,叫什么呢。就是如果我们把此时的这个戏为代表的啊,这块呢,就体现了有一些数据了。
20:06
然后呢,这块呢,如果我们看成是具体的这种代码逻辑的话呢,我们可以理解成呢,就实现了叫数据和代码的一个分离哈。当然这块大家理解呢,可能感觉差点意思,因为我们这个题目的话没有那么复杂了。啊,再说一下啊,你看这个P的话呢,我们是作为一个共享数据呢,传递到各个。啊,线程当中了,那他呢是实际上就是共享数据了,就是你把有共享的数据呢,就都封装在它这里边儿了。然后具体呢,调star方法大调run run呢就是你要处理的具体逻辑啊,我们的代码逻辑,代码逻辑跟你这个,诶,它里边的这个数据呢,就体现了一个叫数据和呃代码的一个分离。啊,因为咱们这个逻辑稍微简单一点,大家可能体会的不是那么明显啊,我就稍微的先往这写一写啊对。诶,实现了代码和数据的一种分离,而这种思想的话呢,以后我们会。经常的去体现啊,数据的话呢,我们单独的就放到相应的,比如说你数据库当中,或者我们在这个呃,程序当中呢,我们会以这种配置文件的方式呢,去存放一些数据,然后呢,代码呢,就是我们相应的这个逻辑了,然后我们可以呢,去读这种配置文件中的数据,然后呢,在程序当中去运行。
21:17
那配置文件这个数据呢,回头你还可以去改。是吧,然后改它的话呢,程序呢不用变,然后呢,还是去读这个文件就可以了,这种呢是我们追求的一种思想啊,一种方式,就好比呢,咱们在idea当中,咱不也是,诶相应的一些配置信息不都写这儿吗。这就体现了叫数据的概念,然后呢,我们这个idea在启动的时候呢,他都会去读这些配置文件的。那大大家当初不也尝试过,有的同学呢,把这个给写错了,然后idea呢就启不起来了,是吧?因为他在启动的时候就会读这些配置信息,如果这里边写错了,他就程序呢就不能正常启动了,相当于呢就出现异常了。啊,这个注意一下啊,这就是数据啊,然后idea这个软件呢,写的时候呢,那个代码就是代码了,体现了一个分离的概念。
22:00
这块呢,稍微的体体会一下,可能不是特别明显啊,这儿呢就是able的一个好处。好,这块我还写了个叫联系,说明他们二者之间呢,有一定的关系。那这个关系怎么看待呢?那这个呢,只能是我来说了啊,那我们会发现呢,当前这个re啊,你看一下他的声明。啊,有恍然大悟。对,你会发现呢,这个类啊,它竟然也实现了renoable的接口是吧。那其实呢,就相当于第一种方式呢,就我们去提供这个thread类的一个。子类是吧。哎,重写run方法,然后呢,第二种方式呢,我不去继承你了,你不是实现了randomable吗?我直接的我也实现re。那大家呢,刚才也提到说共同点呢,他们都有run方法,其实你会发现第一种方式我们说呢,去呃重启的叫read类的这个软方法,其实是因为TH类呢,它也。对它呢,相当于重启了,或者要实现了reno里run了,我们第一种方式呢,是又把它的这个run又给覆盖了是吧,而第二种方式呢,我们就直接呢去覆盖在它里边。
23:08
其实呢,这种写法对于我们这个实现的方式来讲,以后大家讲设计模式的时候,哎,你会发现呢,咱们第二种这种实现的方式的写法。这不就是个接口吗?然后呢,这呢是一个thread这样一个类,它继承了它了,是吧,我们第二种方式是不是自己写了一个类,也这个thread这个类呢,实现了这个reable了,然后我们自己写了一个类呢,是不是也实现reable了。这种方式呢,其实就是代理模式。哎,这也是一种设计模式哈。怎么叫代理,它就叫代理类,这就叫被代理类,就是这个我们实际上是想执行这个实现类的这个入方法,但是这个入方法呢,通过我们这个实现类呢。帮我们去代理执行的,最后执行的还是你。大家可能有点懵,也不用去细究。哎,我就这样一说,你一听就完事了啊,咱们在这儿呢,不去重点说代理模式。
24:04
诶等以后呢,我们讲到这个框架,比如spring的时候呢,我们到时候会讲这个代理模式的。OK啊行,那既然说到这儿了,稍微的再把这个细节呢,再看一眼,看哪儿呢?哎,你看这儿啊。注意看你是不是也有这样的一个疑问。或者你没有的话呢,我抛出一个问题,你看你能不能解释哈。你看我们这儿呢,是不是调TH的这个star方法。这个方呢,咱们起的它的作用呢,第一个启动线程,第二个调用当前线程的run方法。我们调用当前现制方法,凭啥就调到你这儿了呢?你是我这个县长吗?也看不出来呀。什么什么意思啊,你看我是不是调当前线上的方法呀。这个线程的话呢,是不是thread。那其实我就相当于是我这个大的方法。我这个start我调的是我的run方法,是不是我上面我自己的run。
25:04
我自己的怎么就掉到。你这儿了呢?咱们第一种方法说呢,咱们就要继承thad类,你把riad类的这个run给重写了,执行的就是你重写的没问题,那我第二种方式,我也没有重写你此right lay啊。我是重写的re里的re是吧?那你咋就执行你了呢?就是这块呢,确实是一个问题是吧,对真实的点是什么呢?诶大家一看这个源码呢,你就明白了啊,他不是吊死弹的方法。哎,再回过来啊,第二代方法实际执行的是人家的内的run吧。好,我点进thread,我们CTR f12一下,我看一下thad里的这个他在做什么事。他这样写的。
26:02
说呢哎,你start掉我这个run,然后呢,当这个target呢,不是now的时候呢,调target target是谁呢一点。Target的是reable。生命的一个变量。那这个变量呢,不等于闹,那到底这种方式是不是闹呢。咱们是不是用过构造器?咱们构造器用的是。是不是这个呀。咱们传进来了一个reable的实现类的对象是吧,这个对象呢,其实就把这个属性给赋值了。你看这不就掉它吗,这个他给往这走。Target在这是吧,往下走走走走走。走到这儿了,你看。这块这个逻辑就捋清楚了啊,就我们自己呢,在代码里边呢,呃,传的一个reno的实现类的对象,是不是就把当前这个类的这个属性给赋值了,是吧,所以呢,当我们调这个star的方法start又调自己的run,自己的run掉了。
27:02
实现类的软了。所以说呢,我们就执行的是你上边的A。实际上就是我们上面的这个软了。能理解了吧?说白了就是这个时候呢,掉人家thread这个,这个thread run里边又掉了你上面的这个。来执行的。哎,这个呢,其实就是我们要刚才我提到的这个,其实就是叫代理模式啊。诶,但是大家这块呢,你要是不清楚,你也不用管那么多,你只需要呢,按照我们这个步骤走就行了,该重写重写,该调调S,一调S它就执行上面乱了完了。这是我们面上看到的实际情况,你得看源码。OK,两种方式咱们就算了。好,那么这呢,我们把两种方式呢就讲完了,讲完以后的话呢,呃,首先呢,咱们先看一下这个课后的这个练习题,这个练习题呢,不是特别复杂。啊,当然呢,这个有点绕梆给你绕进去了。来我们看这道题啊,这道题的话呢,首先有一个类A,它继承于thread,这呢是重写了这个run方法,然后有一个B呢,也继承的是thread,它里边呢声明了一个A。
28:10
然后呢,还通过这个构造器的方式呢,把这个A呢做了一个初始化,然后呢,它这里边儿呢,也重启了的这个run方法了。哎,这个没问题好了,然后呢,你看上边这个呢,是创建了一个A的对象,A呢调大的方法。这个呢,其实就是典型的我们第一种方式是吧,诶继承threat类的方式,所以呢,这是我们调start,大家你始终要注意这个事儿,咱们不管是继承也好,实现也好,掉的都是RI的这个类的那个大的方法。然后人家这个十大方法呢,咱们提到过有两个作用啊,第一个作用呢,叫做启动线程。这是第一个作用,然后第二作用呢,我们说呢叫调用啊,这个线程,这个线程呢,你可以理解成就是咱们这个re类啊。调用这个thread类的。
29:01
软方法。那刚才呢,有同学呢,去看这个圆码的时候呢,说找不着这个run了是吧,诶你调了一个star方法,说诶调这个这个里边呢,去找run你找不着,因为呢,它里边你看掉了一个START0,这个零的话呢,是一个native的方法。你这就看不着了,因为咱们现在讲的是Java代码里边的线程,实际上呢,我们这个线程最终呢,还都得是由操作系统来帮我们做的这个分配哈,所以这块你看不着,看不着这个RA是正常的,我刚才讲的时候呢,其实我刻意的就避开这个事儿了。因为我带着大家看的是不是API呀,API的时候呢,说掉转了,所以呢,你就看到它掉了,我没有继续看。啊,是有道理的是吧。嗯,因为你看不着嘛,是吧。啊,这个明确就调threat run,然后这个run的话呢,你不是给重写了吗?这就体现这种多肽的这种特征了,是吧?诶这个呢,我们直接呢调这个run方法重写,咱们说广义上也可以看成一种多肽了,所以呢,第一个它的执行是不是就输出的是它了。
30:02
没问题,好,然后第二个我把这A呢传到这儿,然后B调方法了,B调你始终坚持这样一个逻辑,它呢调的还是你自己,这个B呢也是一个实现类了。是不是你也重写了,那是不是还是调你这个方法了。哎,所以这块呢,执行的是不是就先成B的run了。你看我这块掉一下是不是就成它了。OK吧?体会一下啊。啊,体会这样的事儿,所以这块呢。讲清楚。啊,整清楚啊,那你说我这块调整调整这个需求。啊,怎么调这个需求呢,你看啊,我现在是把这A呢传递到这儿了。然后呢,我们这个里边呢,是这样写的run,你说这块呢,如果我把这个代码呢,我这样改一下哈,我这块改成了,呃,重写这个run方法,我改成调A的啊,当然这个调A的run的话,肯定就跑成这个run了是吧。嗯,那我这个我不这样改。我这么着啊。这个构造器。
31:01
CTRL一下。哎,我这样改看大家还能看懂不?诶,我把这个呢注释掉啊。首先呢,你发现呢,这不报错。哎,这个A呢,我们能调super super这传到super里,Super呢,就是我们thread这块呢,这个A呢,你看我们调的是哪个构造器呢,这块呢,用的这个target是吧。哎,那就相当于呢,我们这个A呢,因为你上面不也继承了这个thread类了,Thread呢又实现了reable了。看看能不能把你彻底整懵是吧?好,然后呢,我这个A的这个实例的话呢,其实它呢,相当于也是一个random的一个情况了。哎,所以这块我就这样的方式呢,做了一个操作是吧。这个操作完以后呢,如果我们这块呢,去调这个上面调这个四大方法,这个执行的呢,是不是其实按说还是你这个的是这个没问题吧。呃,那我们怎么改一下,他能调就调我们这个了呢。怎么怎么就能掉了,这个方法我给大家注入掉。
32:02
你看。握住掉以后呢,此时呢,我们这时候呢,调b.star方法,它是不是就调它自己的run,它自己的run。他怎么做的呢?他是不是掉他这个target了。而他这块呢,我们是不是拿这个A给负的值了。那这时候是不是就掉成A了。来,走一下。你看这时候不就掉成了吗。嗯,这个呢,就相当于故意给你整蒙的哈。哎,如果彻底给你整蒙了,那这个就成功了。诶太绕了是吧,诶所以这块的话呢,其实大家你就听我这块讲一下就得了哈,诶你别最后呢,就是都不知道该怎么去写了,怎么写呢,回归到最初的这块,你就按照这个标准,老老实实的就按照这两个方式去写,刚才呢,我这种变形啊,其实就是。哎,纯粹的就是想给你来回倒腾一下,看你能不能整懵了,整懵懵那说明这块呢,你掌握的比较好。
33:04
这个先整清楚以后,你再看我刚才这个变化啊,当然了,我看有的同学呢,还有呃。也比较特别的这种写法啊,稍微我比如说就放到咱们这个练习这个位置的啊,哎,我就要ER我就写一个。二一吧。哎,什么意思啊,你看刚才我们讲了,有这种继承的这种场景,也有这种实现的场景,我就简单一点了啊,这个叫A让他俩去继承咱们这个thread。诶,然后在这里边呢,去重写这个方法是吧,诶这呢是一种场景,然后呢,我们还提到了说这个class。这个我们比如说叫BB啊,让他呢去implement一下,我们这个random。诶,然后呢,Ctrl a一下,把这个方法呢,我们做一个重写是吧,这呢,我们就涉及到了这样两个大的这个场景,然后在这呢,比如我写个may方法,然后呢,有的同学呢,他就。这么着去整了啊,你有一个thread。在那叫个大。哎,如果呢,在这个位置呢,我们整一个。
34:00
打括号是吧,这呢相当于呢,我们把这个入方法给重启一下,这其实呢,就想用继承的方式了,而且是一种匿名的方式是吧。然后呢,你这样写呢,没问题哈,但是呢,有的同学呢,他自己又在这块的话呢,又怎么着呢,说BB。哎,一个小B,然后有一个BB,然后呢,把这个B呢,就给扔进去了。啊,这块就执行了是吧,这块一执行的话呢,倒是也能出来结果就是有点懵了,所以说这到底执行是B的里边的这个run呢,还是执行这个run呢。这是哪个啊?啊,成功的大家也给整懵了。这个呢,我来一个CC吧。那你说我这块执行的,执行的是什么呀。是CC吧?为什么是CC啊?对,你看你这块就是继承的方式是吧,就是你这个大方你始终坚持呢,它调用的是right这个类的软方法,你这块给重写了呀,这是子类嘛,是吧,你子类这块重写,那我当然就调你了。
35:09
是吧,跟这个没关系啊。啊,因为你要没重写的时候,你看注释调。没重写吧?没重写的时候呢,掉的是thread那个run了,那个run里边呢。掉的是不是target target的话,你在这儿是不是用A。用这个给。填充了一下是吧,我要把它注掉,现在指定是谁。逼逼了。是吧,诶同学已经是。大脑已经开始晕了是吧,然后还有同学呢,就是这样写的哈,New一个,然后这块叫一个start。然后呢,就这样写的,或者说这块呢,整了一个大括号,然后上面这个注释掉了啊,然后把这个呢一执行,发现这啥也没有啊。这能有的话呢,就比较奇怪了,就是吧。对,你这个start方法里边调自己的run,自己的run呢,也没有去提供一个target,这不就相当于是一判断没执行就没结果嘛,是吧。
36:06
哎,说白了就是你呢,既不能说啥也不整,也不能整的有点。太重了,整过了是吧,换换句话说呢,你这个方式里边呢,既有我们的所谓的第一种方式,又有第二种方式一样是吧,这个呢,相当于是既不是第一个也不是第二个。啊,你就老老实实的按照我们这两种方式去写。诶,刚才呢,我这种变形啊,其实都是呢,基于这两个基本点来的,如果有点懵,还是回归到最初,把这两个整清楚以后,你再去考虑我刚才写的这个代码。OK,然后另外呢,稍微给大家说一句就是。咱们在这个这一章呢,讲的叫多线程问题啊,当然呢,尽量呢运行这个程序的时候呢,都使用这个main方法,嗯,就不要使用这个单人测试了,单人测试的时候呢,你去运行,你往往看到这个结果呢,可能显示的不全,这个呢跟单元测试有关系啊,不是我们代码写这个问题啊,用没方法去测试呢,比较准啊OK。
我来说两句