00:00
那在讲完呢,如何创建多线程以后呢,咱们来看下个问题啊,关于呢,线程当中常用的方法和线程的生命周期啊,首先呢,来看第一个问题叫线程当中常用的这个方法,当然呢,说方法之前呢,包括这个构造器呢,我们也讲一下,那不管呢,我们是第一种方式还是第二种方式呢,其实呢,都跟这个SH是相关的,所以这里边我们讲的方法呢,其实就是thad的这个类里边这个方法了,那首先的话,我们先看下这个thread这个类当中这个构造器的一个问题啊,来回到我们这个课件这层面,直接呢,我们找到这个三。那首先的话呢,我们看一下这个thread类呢,它长的构造器这儿呢,我是放了有四个来回过来,我直接呢就粘到这儿。那第一个话呢,咱们都比较熟悉了,呃,咱们在使用这个相当于呢,第一种叫继承的方式的时候呢,咱们其实呢,是创建它的这个此类的对象了,那此类这块呢,咱们在写的这个thread里边。啊,在我们上边。呃,这个类的话呢,我们没有提供构造器,那没有提供构造器呢,那我们在造对象的时候,其实就是空单的构造器,空单构造器的这个首航呢,又是super空了,那这时候呢,相当于就调用了我们这样一个构造器了。
01:04
啊,虽然我没有直接的去使用,那么第二的话呢,咱没有用过,第三个呢,用过第三的话呢,就是咱们实现的这个方式啊行参呢,我们传了一个renoable的一个实现类的一个对象了,在这儿呢,我们其实看到还有一种方式啊,就是这样的,包括呢,这里边还有一个带一个reable,同时呢,带一个四中心的name,然后这个name的话呢,其实就给我们当前这个线上呢命名的啊这两个的话呢,我们可以呢稍微的做一个测试。这块呢,不妨我们就随便呢,挑一个我们的实现的方式了,比如我们就拿这个继承的方式来说吧,把这个代码诶从这到这儿啊,咱们CTRLC来粘过来,这个对应的叫even number test,好,那我们就在这个里边啊,右键新建一个。啊的一个test OK,好,那么把我们这个继承的方式呢,咱们就拿过来了啊。啊,这个呢,他把这个呢也给我们过来了。这就没必要了啊。好,那上边的话呢,有一些东西呢,我就把这个文字性的内容,咱们就暂时的都先去一去了。
02:10
哎,这么着啊,把这个我们也都删一删。诶,时光保留我们现在要说的这个核心的这个问题,那这块线程的话呢,我们就提供一个分线程啊,这个下边是主线程的,好,那针对于这个代码的话呢,我们稍微说一下啊,那我们首先呢把它去做一个运行。诶,这里边呢,写made的呢,就我们这个主线程杠零呢,就我默认的这个分线程它的一个名字了,那我们也可以呢,在当前这个类里边呢,我们去写一个这个构造器了啊public,哎叫print number,然后这个呢,对应的是一个空参的,我们可以再来一个啊,诶print number这个呢,我们就可以写一个叫string形的一个name。然后在这里边呢,我们去调了一个super name,哎,这样的一个构造器,这个对应的就是我们说的这样的一个构造器了。好没问题啊,然后回来以后呢,我们在这个位置呢,就可以呢,在行三类位置呢,去起个名,比如说呢,就叫做县城一。啊,相当于就掉咱们上边的这个构造器了啊,然后呢,它呢,就掉了我们刚才提到的这个构造器。
03:06
诶这呢,就给这个县城呢,就命了名了啊,那命名以后呢,我们回过来,我们再去做一个执行。哎,做一个run。好,那这时候呢,你会看到我们这个线程名呢,就改了啊叫做先程一了,诶相当于呢,这儿呢,就是给属性赋值的,就我们叫线程名的这样一个属性,然后呢,上面这块呢,Get name就是获取这个名。啊比较好理解啊行,这个呢,是我们说的这个构造器的事儿,然后这种方式的话呢,其实也比较好理解,就是当我们要是使用这个实现的方式的时候,诶,然后呢,这块你可以顺带着把这个名呢也给它起上。那就行了啊,这个我就不多说了,然后呢,下边我们看一看这个线程里边常用的方法都有哪些,那其实呢,不知不觉呢,我们已经用过一些方法了,比如说首先的话,我们提到这个叫star方法。哎,这个啊,这个方法的话呢,就我们线程当中的它的作用呢,非常明确啊,第一个叫启动线程。哎,第二个呢,我们说叫调用。
04:01
哎,调用现成的这个叫哎,Run方法。OK啊好,那么自然而然的话呢,我们就遇到了第二个方法,这个方法呢,就叫做这个run了。OK,这个run方法的话呢,是我们这个thread这个类里边的这个run方法,哎,那我们也看过这源码了,它的内部呢,其实就调这个叫target的一个run方法了。啊,所以这块呢,我就先简单这样写一下,这个run方法呢,我们可以理解为呢,将呃线程。哎,将。啊线程啊,要执行的这个操作呢,我们现在也声明在这个run方法中。啊,现在这个run的话呢,就是我们现场上要做的事儿,OK啊好,那这个完了以后呢,我们其实还遇到了一些,比如说用过的哈,叫current thread。哎,这个呢,我们其实也用到了,比如说我们在刚才这道题目当中这个位置。它呢是一个静态的方法,诶,通过这个类呢来进行调用呢,叫获取当前的线程。在当前执行代码对应的这个线程啊。
05:04
行,那回过来,你比如说我们这段代码呢,是在哪个线程中执行的呢?显然呢,就我们这个七一这样一个线程了啊,对应的这是它的这个名,然后下边这个代码的话呢,我们调这个current thread,其实就是我们这个main方法对应的这个线程啊,也就是说主线程。OK,所以呢,这块呢,就是获取当前的这个线程,那自然而然的它这个返回值的话呢,其实也就是一个具体的线程。OK啊,这呢,你看还是一个native的这个方法,呃,在这一章里边呢,我们关于thread呢,会看到一些native的方法,但是因为呢,我们其实本质上来讲,这个线程呢,都是由操作系统呢,来给我们做的这个分配啊,所以呢,它会调用到这个native。哎,这是个他啊,然后呢,这块呢,还有一个方法,那我们刚才也看到了,叫做get name。那我们得到一个具体的线程以后呢,这个线程的对象呢,就该name,就获取这个线程的名称啊,所以这个呢也比较简单。这个我们叫哎获取线程名啊,诶这个比较简单,好,那既然有这个get的话呢,我们就会想到说是不是也有对应的个site,诶事实上的话也有,那比如说回过来,那就比如说我们在这个位置呢,叫县城,一给这个县城起了名了,让他start了,然后下边这块呢,诶它呢默认的就是主线程,主线程呢其实也有个名。
06:15
啊,就叫妹说我能不能给这个主线上也改一下名。其实也可以是吧,那我们比如说就在这个位置来改了,那我这块呢,应该怎么操作呢。对,首先呢,这个thread啊,点current thread,这不就拿到这个主线程了吗?然后我们去set name就行是吧,比如我们就称为呢叫主线程。诶这样就可以了,然后呢,接下来你再去get name的时候呢,这时候呢,就叫主线程了。哎,你看这时候就要主线程,哎,没问题啊行,那你要说我们上面这个,我想也改一改,那也没问题,那当然这块改的话呢,最好你是不是在start之前去改啊。啊,要不12时候他都已经呃运行起来了,都是吧,对就不合适了啊好,那这块我要是改的话呢,怎么改呢。
07:02
哎,这个时候呢,你注意我们这儿呢,你不能写thread current thread这时候是不是还是主线程啊。对,因为呢,整个我们这个对象的创建,这个分线程的一个启动,这都是由主线程来帮我们去做的,当它启动完以后啊,然后呢,这个分线程才开始去执行的,所以在这块你写这个th current thread,那肯定还是我们这个主线程啊,这个是不靠谱的,那因为我们这个类呢,它不是本身已经继承了thread了吗?所以它其实就是线程是吧。是你T这个线程啊,直接呢调S内是不是就可以了。哎,比如我们这个呢,叫做子线程一。啊,也可以。这呢,就相当于把这个名呢又给改了。诶这呢,不就相当于我们在一个呃实例变量啊,通过构造器呢,可以赋值,还可以通过方法呢,给大家再去改这个值吗。啊,没问题啊。好,那么此时呢,我们再去做这个run。哎,这不就改成叫子线程了,就。哎,就这样啊好这呢我们就过了啊行,这个S内呢叫设置先程名。
08:05
行,这个呢,相对来说都比较简单一些哈,然后接下来嗯,我们再看有哪些方法呢?嗯,比如我们先说一下这个吧。后边呢,我们再去做相关的测试的时候呢,会用到这样一个方法,这个呢叫做sleep。这块呢,会写一个具体的一个毫秒值啊,一个数啊,举个例子,比如说啊,我们在。啊在哪,在这块吧。诶大家看一下啊,这呢是我们这个分线程,然后呢,每循环一个I的时候呢,我们这个位置呢,可以写这样一个操作,我这呢叫做th.sleep。啊,你看到了,我直接通过这个泪呢就能掉,说明呢,它也是一个静态方法啊。对,然后这块呢,比如我写个1000,这个对应的是毫秒,1000毫秒。对,就是一秒钟,哎,所以这个呢,相当于是让我们当前这个线程呢,睡一秒钟。诶这个意思好,那这个s sleep的话呢,它本身呢,它会这个默认啊,它会相当于抛出来一个叫非运行时异常了,那我们这时候呢,就一定要考虑如何去处理是吧。
09:07
那处理的话呢,按说有两种方式,一种呢叫try catch finally。啊,一种叫肉是吧。哎,正常来讲的话呢,一个方法这块,如果有一常我们alt加回车就会给我们提供两种方式。但是现在呢,你会发现呢,他这只写了一个try catch。这个意思哈,但你看我这儿啊,我把它CTRLC一下,比如说在我们这个may方法里边,诶,我就随便找个地儿,比如我就写这儿了啊,那它这块呢,也会报这样的一个变异式异常了,我这种呢,Alt加回车。你看是不是写了俩。哎,这两个的话呢,其实。第一个它对应的就是这个Rose啊,第二呢就是catch哈,那你看为啥我们在这个位置的时候呢,我out加回车,它就只有一个呢。对,相当于呢,不让我们死肉是吧。你觉得为啥呢?
10:01
啊,这块呢,它只能让我们这样去写是吧,诶prince,对,因为的话,你看如果我们要是Rose的话呢,是不是就在这了。那这个的话呢,让不让我们在这加呢,取决于咱们继承的时候呢,这个是吧,它的这个run方法呢,咱们搂一眼啊,或者我们直接在这儿也行哈,在这我点它也行是吧。你看我这块我一点。哎,在咱们thread里边这个软,它没有throw任何的异常信息,所以说我们重启的时候呢,你也不能够去throw。诶,咱们前面讲重启的时候呢,这是一个规则嘛,是吧,诶这个小细节啊,稍微注意一下好,那么这儿呢,我们就这样来去处理了,然后主线程这块呢,我就不考虑了,是吧,把它就去掉。行,那么这个的意思呢,刚才大家也都知道了,那我们现在去运行一下这个程序,你看这个效果啊。诶能看到是吧,咱们这个主线程的话呢,我没有让他做任何的sleep,所以呢,它的执行速度就非踌快了,一下子就全执行完了,然后呢,我们这个死线程这块呢,因为我们每进来一下它都得诶停一下是吧,一秒钟,所以这块你看到它这个执行的就比较慢。
11:09
啊,这要慢一些啊,这就成这样一个效果了。这呢就是我们这个它的一个执行的效果啊好,那我们回头来说一下,这个位置呢,可以写一个long类型的叫A。哎,说呢我们,呃,首先呢,这是一个静态方法啊。啊,可以说调用时。啊,可以使得,诶当前线程,哎,我们说叫睡眠啊指定的。哎,好描述。哎,就是这样一个作用。好,这个呢,叫做sleep了啊,然后呢,我们再说一下这个方法,嗯,好。哎,这个呢,叫做已有的是吧。业务的什么意思,来,我们过来稍微说一下啊,这儿呢,我们把它呢,暂时呢,咱就注释一下了。然后的话呢,我们这么着哈。
12:01
在这儿。然后呢,我在这块呢,比如再加上个if哈,说如果呢I呢,我们就要取模20啊等等于零,相当于呢,你如果是20的这个倍数,我们就怎么着呢,哎,我叫Y一下。啊,Y一下,我这块写完业以后呢,它这块啊,提示我们这有一个信息是吧,我们现在呢,是在当前的它里边thread呢,我们先进来啊,然后呢,Controlr f12啊的。给他是吧,他这是一个静态方法是吧。啊,相当于这块呢,他建议我们这样去调了,也这么着。是吧?这个yield是什么意思呢?啊,就是一旦呢,我们要是执行到这行代码的时候呢,他就主动释放CPU的执行权。哎,他一释放的话呢,那么这个CPU呢,下一刻很有可能就不执行了。哎,那我们看这个效果的话呢,就可能会看到这样的一个情况,所以你看我这边说的是可能哈。这个子线程啊,我们找,嗯,诶。
13:00
哎,就以它为例吧,我们这个子线程的话呢,执行60了,相当于这块呢,就是把60给输出了,输出完以后的话呢,下一刻呢,CPU可能还会执行它,那这时候呢是60曲目20呢是相当于零的,所以我们就执行这叫业务的了,所以呢,下一刻呢,你可能会看到呢,这个CPU的执行权呢,就分配给另外的一个县了。因为他主动的释放了。哎,那么CPU执行权呢,就给到另外一个线程是很正常的,当然也有可能你看不到这样一个效果。嗯,啊,这块还都有是吧。20的时候。啊,这个呢,效果还挺好的哈,都有啊,有可能你看不到,也就是呢,子线程一这块直径的20以后呢,有可能下一刻你又看到是子线程一二十二。就相当于他释放了CPU执行权,但下课呢?是不是又让他给分配到了?啊,这个也是有可能的哈,这个呢,就是我们这个业务的它的一个作用,诶稍微的我们在这写一下啊,就是呢,呃,一旦执行此方法。
14:00
啊,就释放。哎,咱们说那叫CPU的这个执行权。OK啊。行,它有点像什么呢?比如说你在这个窗口,咱们去这个车站买票是吧,这块大家都在这排着队,然后到你这块呢,诶你说你想买到哪个地儿这个票啊,他告诉你说这个票已经卖没了是吧?啊那这时候没办法了,你得想办法,比如说。中转一下是吧,但一时呢,你可能想不到说你这块稍微等一下,你跟下个人说说你先来。是吧,这块呢,就相当于是你业务的一下是吧,先让他先买票。啊,注意有点像这样的场景下啊,主动释放CPU的执行权。好,这个完了以后呢,我们再说一个啊,这个方法呢,叫做John。啊,这。对,上面这个呢,我们刚才提到了,它是一个静态的方法。OK,然后这个照的话呢,它不是静态方法了,呃,需要我们主动的拿一个现成的对象呢去调它,那回过来,诶,我把这个呢,暂且先注释一下啊。然后再下面。
15:01
下边我看在哪呢。比如说我们在这个位置。啊,这儿呢,是咱们这个主线程啊,主线程这块呢,我们写一个说if。当I呢是20的时候。那也就是说,当我们这个主线程呢,刚打印完20以后呢,它就进来了,进来以后干什么事呢,我这个七一呢,就是这个线程让他呢去调一下,这个叫状语方法。啊就掉了啊,然后那个罩的话呢,本身它也会去抛出异常,所以呢,我们也给他呢去诶暂且呢叫拆开的方式,我们去诶处理一下。好就这样了啊好,那么这个操作呢,是什么意思呢?咱们先运行一下。哎,我们看到这样一个场景,往上走。诶,刚开始的时候,你发现了两个线程交替这样的去打印,然后呢,一旦我们这个主线程执行完20以后。那你会发现呢,我们这个死线程接下来呢,它就一路呢往下走,一直呢,执行完了,然后我们这个主线程才继续开始执行。
16:00
那这种情况的话呢,我们可以再夸张一点,比如说我们让这个,诶孙先生呢,把这个再打开啊。把这个打开以后呢,你看我们此时呢,再去做一个run。好,大家你看啊,因为呢,我们这个分线程这块呢,有一个sleep,所以呢它执行的比较慢,所以你会发现这个主线程一上来它就啊一路呢就到20了。然后呢,到这以后的话呢,我们就执行了下边的这个叫join操作。那一直行照完操作以后呢,你发现这时候呢,此线程就开始执行,而我们这个主线程。即使在子线程税的情况下呢,他也不执行是吧。那什么时候他会执行呢?诶,直到咱们这个子线程执行完以后是吧,诶它才会执行,所以这呢,就是我们这个照方法它的一个作用。啊好,那回过来啊,那我们这儿呢,怎么去说呢,比如这样啊说呢,我们在这个,呃,线程A中啊,调用或者叫通过啊线程B。哎,调用叫照应方法。
17:01
啊,那么这个意味着。哎,我们这个线程A呢,就进入阻塞状态是吧,直到。哎,直到这个线程B。哎,执行结束是吧,然后呢,线程A才结束阻塞状态继续执行。哎,就这样一个场景,那刚才呢,咱们就相当于在这个主线程当中调用了咱们那个T的这个线程。啊,T1的这个线程,然后他就join,然后呢,这个T1线程直到执行完了以后,我们这个主线程才会继续的执行。OK啊,那这个呢,什么时候用呢?那你比如我们这块有个线程,它正在这个执行,那执行到这块的时候呢,它需要呢拿到一个结果,而这个结果的话呢,需要联网来获取,那这个结果的话呢,我们就,呃,既然联网了,它是一个比较慢的事儿了,所以我们就利用开了一个线程,这个线程专门就联网来获取这个数据的,好那么到这儿的时候呢,我因为要用这个结果接着往下执行了,但是这时候我们还拿不到这个结果,不确定,那怎么办呢?这个我就调你这个线程的一个照的方法了,然后等一下你是吧?诶当你把这个结果给我以后,你就执行完了,执行完以后呢,我拿着这个结果呢,我再继续的向下执行。
18:14
哎,这个我们就理解成是这个John的这个操作了。啊,体会一下行啊好,这是我们说的这个John,然后这个完了以后啊,我们再看一个,嗯,我再看一个这个方法啊在这儿。这个呢叫is。Alive。哎,你看这名字呢,应该比较清楚啊,说判断当前县城是否还存活是吧。在现场是否存活,哎,所以呢,它的反馈结果呢,就是一个布尔类型的一个值了,OK啊,那回过来举个例子啊,我们主线程。啊,走到这儿的时候,哎,我这呢,判断一下这个七一这个线程,你是否叫is alive。啊,然后这块我们打印一下啊。
19:06
这个我们叫。哎,子线程一。CTRLC啊。他呢,是否存活?哎,这呢,我们连接一下。哎,这么着好,那你想想,由于我们这块已经是让T7线程呢,它照应进来了,它只有消亡以后啊,T7线程它执行完以后,我们主线程才能继续的往后执行,那主线程这个循环都执行完了,那你子线这块肯定早都已经消完了。上面我们把这个sleep呢给大家注释一下了啊。好,这块我们再去做一个re。哎,结束了啊,主要是我存活呢,False诶已经死亡了,实际上呢,在我们这块呢,执行结束以后呢,你这个磁线呢,就已经死亡了。诶OK,这呢是我们说的这个方法了啊好没问题,这呢是我们给大家呢提到了这样的有一波方法,这里边呢,有一些方法呢,会影响咱们线成的生命周期,所以呢,我们这里面就讲了,讲一会呢,我们看一下线上的生命周期,OK,好,那这完了以后呢,还提到了有过时的方法,也就是呢,被depreated去修饰了啊这个呢,我就简单的这块呢去说一下,哎,典型的一个方法呢,叫做stop。
20:11
哎,你一看这名呢,也非常的清楚,我们通过一个线程调stop,是不是直接就挂了就。啊,线人就死亡了是吧?哎,这呢stop啊,不建议使用它呢,叫强行结束一个线程的执行,直接呢就进入死亡状态了。啊,那线程正在执行呢,你突然的第2STOP这个线程就挂掉了啊,那么如果咱们这个run方法呢,此时还没有执行结束。啊,那这时候呢,就导致呢,我们这个程序呢,相当于就啊有些工作呢没有完成,所以这个方法的话呢,我们其实是不建议呢去使用的。OK啊行,咱们把这个事儿呢,给他拿过来,大家做一个了解就行啊。在呢,不建议使用。诶,这呢是他啊,然后除了它之外呢,还有一对方法,这一方法呢叫做resume和这个叫suspend。
21:01
这个SP的话呢,它就是一定要这个方法呢,就把这个线程给挂起啊,所以这挂起呢,其实也是一个阻塞状态啊,就类似于呢,咱们这个音乐播放器里边这个暂停键一样啊,然后这个resume呢,就相当于是恢复键。对,所以你暂停得有一个恢复,他俩呢一般呢都是配对使用。哎,但是这两个调用的时候呢,你处理不当呢,会导致呢,这个线程呢,就进入这种死锁的状态了。哎,就是这块挂起了,然后呢,诶没有去调用这样相关的功能,然后呢,相应的资源呢,如果互相调用啊,这时候呢,会造成思索,什么叫思索,咱们后边去讲啊,所以呢,这两个方法呢,你就记住这个结论,就咱们也不用了是吧。哎,回过来。哎,就这两个方法啊,说可能造成。诶死锁,所以呢也不建议使用。哎,不建议使用,OK啊,这呢我们就清楚了。好,那么这块呢,我们就讲了一些方法,实际上呢,这块提到了下一个问题叫线程的优先级啊,优先级的话呢,我们这块还对应着有几个方法,所以呢,我们把这几个呢稍微的再提一下啊呃,那一提到这优先级,我们就回到呢,前面讲这个县城这块的时候呢,提到一个线程的调度的策略,提到一个抢占式啊呃,Java这块呢,选择的就是这样的一种方式,就是高优先级呢要。
22:21
呃,叫什么以较大的概率呢去优先使用CPU,所以呢,他优先考虑被执行。行,那么回过来。啊,找到咱们刚才的这个操作啊。啊,对应的我们这方法这块,呃,首先这块呢,我们对应的有一个方法叫get priority。啊。Priority呢,就是优先级的意思,所以这个方法作用呢叫获取现成的。优先级。啊,咱们这个县城的话呢,没有指定过优先级,它其实也有一个默认的优先级,那回过来。比如说在咱们这个代码层面啊,我在这块打印当前线程的名,打印这个it值,然后顺带这块呢,我们就把这个优先级呢,咱们也给它打一下,这块呢,就这样写了啊th.current th.get一个叫priority。
23:08
哎,这不就获取他的优先级吗。咱们这块呢,也整一个。啊,这么着啊,这个加个冒号吧。哎,这个有点长,咱们换下行啊,这呢是先生名,这是县城的先级,然后呢加个冒号加个I。哎,这么着的好,然后把它呢,CTRLC咱们也在这个主线程当中。哎,在这块呢,咱们也给它这样的操作一下,哎,CTRLV粘过来,然后这个照的话呢,暂且咱们就诶注入掉了啊这个呢,Is alive呢,咱们也就逐跳了。好,然后呢,我们做一个run。改出来了啊好,那么这时我们会看到这个主线程或者这个分线程呢,默认的优先级呢是五。啊,这是我们说呢,正常一个线程的优先级,那我们在设置的时候呢,可以比五小啊,也可以比五大。那这块就涉及到了,诶我们这个县城医年级设置的一个范围是多少。
24:03
啊,这块咱们课件里边这块我有写哈,就在这儿。在咱们这个里边呢,它有一个有三个这个常量啊,分别对应叫max priority mean priority和priority。哎,咱们刚才呢,说优先级是五,就是呢,默认情况下呢,咱们就是五。啊,那么除此之外的话,我们提到最低的优先级呢是一,最高的呢是十。诶,所以这块呢,我们先把它呢CTRLC啊拿过来,需要呢,大家诶熟悉的是这个事儿啊,这呢就相当于是线程thread类。诶内部,哎声明的三个敞亮,哎,就是他扫啊。哎,这块的话,我们通过这个thread呢,也能够找得到啊,CTRL f12,诶我们去找一下。哎,在这儿呢,哎,这个呢,就是max的,这个是normal的,就是默认的啊,然后呢,Min最小的,诶这呢就是我们说的这三个常量啊。
25:00
好,那这块呢,看清楚以后呢,那我们回过来,诶知道呢,默认的预先级呢是五,那我们既然能够get就会考虑呢,是不是就会有set啊确实有。哎,这个呢叫set priority,就是设置线程的优先级,然后自然而然的这个范围呢,就是。一到十那就是吧。OK,好,回过来。那咱们这块呢,做一个设置哈,设置的话呢,咱们比如说改改这个主线上的吧。这呢是改主线上的这个名,这呢直接去调它了,我在这个调之前,咱们这么着啊,点current.set priority,咱们把它设置优先级,比如高一点。啊点叫max priority。最大的优先级。行,它设置成最大了,咱们回到这个分线上这块。诶分线程这块,我们要设置这写哪儿啊。哎,建议呢,你就别往上写了,我们在执行run之前是不是给他设置一下。
26:00
所以就在这儿写吧。改T一点,Set priority改成一个,比如说thread。第二,我们来一个叫M吧。最低的。哎,然后呢,设置完以后,再让这个线程呢跑起来。哎,竺先生呢,我们是写到这儿了。那么这时候我去运行,哎,大家你注意看啊,这个所谓的高和低啊,意味着什么。发现一个点不。他们还是有交互的,你看是吧。啊,就是按照我们的理解呢,可能会认为说你这个主线程的先级呢,很高了,或者说最高了,子线程这个最低了,说是不是意味着这个主线程呢,得先都执行完以后,子先生才开始执行呢。对,你发现并不是是吧。哎,如果真要是那样的话,那不成了单线程了吗?是吧,他执行完了以后,他才开始执行那么单线程是吧?哎,他既然是多线程的,就是还是会有交互的,只不过呢。呃,由于我们这个线程的优先级比较高,只能说呢,它被CPU呢执行到的机会呢要大一些。
27:05
从概率上来讲,但是似乎呢。呃,也看的不是很明显是吧。对,这个呢,其实还有原因是因为咱们是核的CPU啊,如果你要纯粹是个单核的CPU的话呢,那这个主线一定是,诶这个被执引概率会更大一点,那多核的,甚至我这是好多个核,这时候呢,其实诶我们现在也没有那么多的这个优先级,这个更高的这个县程之外呢,那这块呢,其实它俩被分配到概率按卓都不低。哎,所以就打印的,似乎你就看着就不明显啊。啊,这个大家注意一下。行,但是这块呢,我们还是要知道这样一个事儿啊,设置优先级的问题啊,这里边儿呢,只是提到了我们优先级高的呢,说要抢占优先级低的这样的一个资源,只是说呢,他从概率上来讲啊,以较大的概率呢优先使用,没说他一定。啊,是优先的。这个大家注意一下这个问题。好这呢,我们就要设置设置优先级,然后这个呢,是它对应的这个优先级的这样几个档档位哈,那你也可以呢,使用他们之间这种的值啊七呀八呀啊二啊三呀都可以行。
28:09
呃,那么这儿呢,关于我们说线程里边常用的方法呢,其实就这些啊,然后加上构造器,大家呢,稍微的熟悉熟悉就可以了。那么接着的话呢,我们来看一看这个叫线程的生命周期。那线程的话呢,我们以前呢,讲main方法的时候呢,没有启他啊,原来我们就正常就执行,执行结束呢就结束了,所以现在的话呢,我们通过调这个四大方法呢,就启动了一个新的线程,然后那个线程呢,就开始做运行,然后最后呢,它消亡了,中间呢涉及到有几个环节,那我们把整个这个过程呢,就称为呢一个生命周期的一个概念了。好,那这块我们就要讲一下这个线程的生命周期,那讲这个生命周期的话呢,首先我们来看一下这个课件哈,这块呢,我先做了一个区分,分成了叫JDK1.5之前和JDK1.5及之后,诶可能有同学说了,说现在都已经JK都17了,我们干嘛还拿1.5来说事儿啊,这个我们说一下1.5呢,有助于大家去理解1.5之后,因为1.5之后呢,把这个情况呢分的又更细了。
29:05
那我们先得有一个宏观上啊,简单的一个模型的一个认识。简单来说的话呢,把这个线程我这儿呢,分成了这样的几个状态,分别对应的叫新建就绪,运行阻塞和死亡。然后呢,JDK5之后呢,针对这种阻塞的情况呢,把它分的又更细了,所以为了大家能更好的去理解这个线程的这几种状态,咱们先说一下这个1.5之前的这个情况,那一边说呢,咱就一边呢来画这个图,所以呢,找到咱们对应的这个课件啊,打开我们这个PPT啊。好这呢,其实我画了一个啊,咱们这块呢,重新画一个,诶我这块画着大家呢一边呢也记一记啊,看看我们这个线程呢,都分成了这样的几种状态。诶CTRLC一下啊,用一下这个标头啊好这呢把线制呢,首先呢,分成了这样几个状态哈,第一个呢叫做新建。OK啊,这个呢,把这个字呢,稍微的变大一点啊。
30:01
好,这个呢叫新建,然后新建下一个呢,我们称为呢叫旧绪。OK,然后再往后的话呢,这个呢叫运行。哎,然后运行完了以后呢,后边就死亡了。OK,哎,那么在整个这个执行的过程当中啊,它其实还有一种状态。称为呢,叫做阻塞。OK。这呢就构成了我们线程的这样的几个状态了,就好,那我们这里边看一看,现在在状态之间呢,是如何切换的啊,首先呢,这个新建的话呢,实际上呢,就我们所说的呢,我们new了一个这个线成的对象了。诶,那拟完以后呢,它就是新建了,这是一个对象,然后呢就绪,就是随时呢CPU呢可以去执行它了,那从这到这儿啊对应的是什么操作呢。对,就是我们去调用这个大的这个方法了。OK啊行,那你新建完以后呢,如果不调start,那这个线程呢,是始终不可能被CPU执行的,那调完start以后呢,就进入这个就绪,好,那就绪呢,接下来我们说呢,可能就被这个,呃,CPU呢选择执行了,从就绪到运行,这意味着。
31:09
获取了CPU的执行权是吧?CPU这个执行权。那这个CPU呢,我们说呢,它无时不刻呢,都在快速的切换啊,他要执行的一些任务了,那如果切换到你当前这个线程的时候,你现在也是就绪状态,那我这块呢,就去执行你了。哎,这是这样的情况,那么从运行的话呢,也是有可能到这个就绪状态的。对,那就意味着你失去了这个CPU的这个知情权。哎,对,我们这个叫失去。是吧,失去这个执行权,这个呢,相当于是西部呢,它因为在切换嘛,所以你可能就失去了,对刚才有同学呢,说到了还有一个方法是吧。这个我们那会儿讲到的叫业务的吧。诶,当我们呢,通过一个线程主动的去调业务的时候呢,就是你主动的想释放这个执行权了。所以它呢,也就进入到叫就绪状态,注意不是阻塞状态。
32:02
这是就绪的。好,他俩的这样一个场景,然后呢,我们这个运行这呢是我们希望看到的,也就是执行我们那个run方法了,那什么时候呢,它会进入死亡呢。诶,你这个run方法呢,执行结束了,相当于我们这个线上呢,其实也就结束了,所以这块呢,是我们正常能够看到的一个场景,那就是run方法正常执行结束啊。这是第一种情况啊。Run方法执行结束好,那除了这种场景,还会不会有其他的一些情况呢?对啊,那第二种典型的场景呢,就是我们出现异常了,而且呢,出现了异常呢,我们还没有去处理是吧,所以呢,这块我写句诶出现了未被处理的啊,比如这块呢,Error,这咱们处理不了的啊,那你可能还会有这个叫exception。OK啊,只要呢,你没有处理的这块,我们相应的就会啊,也停止了,呃,另外呢,其实还有一个第三个情况,就我们提到一个过时的方法。
33:02
Stop是吧?诶,当我们呢,一定要用这个stop的时候呢,这个线程你从应用状态立马就进入一个死亡状态了。OK,这是我们对应的这样的几个情况啊,这个咱们稍微的字小一点啊。好,那么这个线程可能从这个死亡状态又回到运行状态吗?回不了了啊,注意这块呢,不能回来,这要回来呢,得多吓人啊,是吧?啊,跟人一样死而复生了成了是吧?哎,这个是不行的啊,死亡呢,那就是死亡了,所以这块呢,它是一个单向的,诶注意。好,那么我们在整个这个执行的过程当中啊,还有可能会出现一种状态叫做阻塞状态。那这呢,我们看一看哪些操作会使得呢,我们一个线程从运行到阻塞呢。诶刚才呢,我们其实讲到了一些相关的一些方法是吧,那其实有一些方法呢,就会出现这个事儿。比如说我们先提到了这个sleep是吧。诶这个呢叫做睡眠了,那如果呢,一个限程呢,执行到此sleep方法以后呢,这时候呢,比如说我这写了1000,那就是有一秒钟,那在这一秒钟之内哈,即使这个CPU呢,想去执行它,那也不行。
34:11
那这个线程呢,在一秒钟之内呢,它必须得是阻塞的。这个呢,就相当是一个sleep。好,它是一个啊,那咱们一边说这呢,一边就这块儿看着这个对应的吧,对应的就是相当于这个线上呢,得从阻塞状态是不是再回来啊。回来的时候呢,不是说马上就到运行了啊,他呢得先到就绪。比如说我们这个sleep这个时间到了。哎,这个呃,时间到这个时间到的时候呢,不是说他马上就执行,你得看CPU这块呢,能不能给你分配资源了,分配资源的时候你才可以呢去执行啊。这个呢,对应的就是我们说的这个事儿。好,那么接着。啊,这就叫sleep了,嗯,还有。哎,对,我们刚才提到这个John是吧。哎,这个状。好,那我们在这个A线程里边调这个B线程点转,那这时候我们这个A线程就进入阻塞了。
35:05
啊,那你这时候呢,什么时候这个线上呢,再恢复过来呢。啊,其实就对应的你这个照的要照的那个线程的执行结束的时候是吧。啊,这个呢,我就泛泛的这样一写了啊。哎,这个照。啊,这个对应线程。呃,现场这个结束是吧,哎,我就这样泛泛的一写啊,大家能理解这个意思就行了。好,那么还有什么呢?诶这块可能会涉及到一些呢,咱们这个还没有讲到的一些操作了。啊讲到一些什么操作呢,你比如说我们这个叫获得,这个叫失去了啊失去这个同步锁。啊,这个呢,也是咱们讲完这个生命周期之后呢,接下来我们要说的这个线程同步机制啊,当你要失去同步锁的时候呢,就进入阻塞状态了。啊,那对应的呢,要获得。同步锁的时候呢,它就能够,哎,进入这个就绪状态了。
36:01
哎,这是一个啊,然后呢,我们在讲到这个线程通信的时候呢,咱们还会提到这个叫wait。对为呢,叫做等待。刚才我们调用这个等待这个方法了,那你当前这个线上呢,就阻塞了。啊,那什么时候结束呢。哎,这个呢,Wait呢,它其实对应的有多个方法啊,它呢有的是带参数的,就有时间的,那你这个wait时间到了,相当于它也就结束了。哎,所以这块呢,就涉及到有这个wait。哎,这个时间到是吧,这是一种场景,另外的话呢,它也有一个就不在这个时间的,那就是一直在这儿等,一直等着肯定不靠谱啊,这块我们会有对应的一个方法。哎,这个方法呢,我们称为它叫notify。那另外翻译过来叫做唤醒的意思。啊,那我可以呢,主动的把你wait的这个线程给你唤醒,哎,就可以了,那我们如果有多个线程被wait了,我们还可以呢,调另外一个方法啊,叫做notify oh,对。Out,就是所有被wait的线程呢,都可以被唤醒。啊,这就是我们说的这样的一个操作啊,这个我这一下吧。
37:03
好,那这呢是提到了这个叫wait了,诶还有什么呢,我们刚才那会儿讲的时候呢,提到了一组这个呢叫suspend是吧。哎,这个呢,就把当年县城给挂起了,那一挂起这个县城就也进入这个阻塞状态了。哎,就他。好,那么它是一个挂起,那你结束这个挂起操作呢,叫resume是吧。诶OK,好,那么这呢,就是我们提到一个线程啊,可能进中阻塞状态对应的一些实际的操作。这呢是结束这个阻塞阻塞的一些操作了,那么这个阻塞呢,大家注意啊,对于我们一个线程的生命周期来讲,这个阻塞我说呀,它一定是一个临时状态啊。哎,临时状态。这个能理解是吧。就是这个线上的话呢,如果它进入阻塞了,它不能一直在这阻塞着,它一定得。到就绪状态才行,否则呢,你这个程序就有问题了。
38:01
啊,他得回到就去,然后呢,被这个CPU呢分配,然后去执行,然后最终的目的呢,最终的这个出路呢,只有一个是吧。啊,从他出生的这天开始,就决定了他最后的结果只有一个。嗯,就是死亡是吧,最终的状态啊,其实我们人也是一样是吧。哎,从你出生那个开始呢,也又决定了你最终状态也就一个就是去死是吧。啊,直播的中间这个环节的话呢,诶看能不能过得绚丽一些啊。好,这呢就是整个我们说的这样一个状态啊,一定要记住,阻塞呢一定是一个临时状态,千万不能让它作为最终状态出现。好,这呢就是我们说的叫生命周期,这里边儿呢,咱们要关注的点是什么呢?首先呢,有几种状态,这是其一,其二的话呢,我们注意这里边呢,是一些方法的调用,导致我们线程从一种状态切换到另一种状态了。
39:00
是方法调用导致状态呢发生变化的。啊,以后的话呢,我们可能还会遇到其他的一些场景,什么意思啊,就是反过来哈。什么叫反过来呢?就首先呢是状态变了,状态的改变导致一些方法会执行。这个。嗯,这个咱们后边会讲一些结构的生命周期的啊,不在咱们基础阶段了啊,诶我这儿呢,只是举一个稍微形象一点的例子啊,咱们还以这个手机为例,大家因为对手机呢,可能比较熟悉一些啊,手机的话呢,你比如说咱们可能会出现这样的场景啊呃,现在呢是一个界面,这个界面呢,以安卓的这个应用程序为例呢,这儿呢,其实这个界面对应的也是一个对象。啊,也是一个对象,这个对象对应的类呢,其实叫activity啊。啊,这个类的一个对象了,好那么嗯,比如说有的时候呢,会见到相应的一些操作,比如我点一下某个按钮,或者我长按的一个图标,它这块呢,有时候会弹出一个框来。这个框的话呢,就是你现在点叫确定啊取消啊,啊这就一个框,这个框呢是个dialogue,其实这块呢,它也是个对象,这个对象一出现之后呢,实际上后边这个对象呢,你现在也能看到它。
40:11
但是你现在不能操作后边。现在必须得操作这两个操作。所以呢,当我们出现这个弹窗的时候呢,你发现呢,后边这个咱们说的这个activity这样的一个对象,它就呢,变成了一个叫可见不可操作的状态。没有出这个框的时候呢,是叫可见可操作是吧,这个框一出现呢,叫可见不可操作了。对吧。完了,懵了。是吧,对对于后边这个对象来讲呢,它原来是可见可操作了,现在它变成了一个叫可见不可操作了,那么中间呢,就会有相关的一些方法的执行,好,那你当你点完这个叫确定也好,叫取消也好,这个就没有了,他也没有呢上后边这个呢,不就又变成了一个叫可见可操作了吗。中间呢,又会涉及到一些方法呢,会执行,所以这块呢,它体现的就是状态的改变,导致相关方法的执行。
41:02
哎,咱们现在讲的呢,是方法的执行导致状态的改变是吧。诶这块注意看是谁是主动的啊,有这样的一个点,好这呢,就我们说的叫现成的一个生命周期了,诶我呢可以把这个图诶到这儿是吧,哎,咱们。复制一份啊,放到这这个我就放在这儿了啊,CTRLV。在这儿啊,Shift f6。这个我们叫哎,线程的生命周期。周期啊,注意我这块呢,想强调点呢,它是我们这个JDK诶五之前。哎,说完了。好,那这个说完之后呢,我们接下来就得说这里五级之后是什么样子的。或者换句话说呢,如果这个笔试面试当中问问到你了,说先生的生命周期有哪几个状态呀,呃,这时候建议大家要说的话呢,说他呢,按说就不太合适了。啊,说了半天,这个我们还不能说啊,当然呢,我们讲它的意义呢,就是大家呢,能够更好的去理解我们接下来讲的这个事儿啊,在这个TH的这个类里边,我们CTRL2。
42:06
他那有一个内内。这个类呢,叫做state。哎,你直接在这写也行啊,哎,State就它,然后这个内部类呢,还是一个枚举类,所以呢,就直接用A来定义了。这呢就是它的几个对象,这个对象呢,其实就表示了咱们一个现成的生命周期了。啊,咱们现在呢,拿的是这个GDP时期来看呢,它其实呢,是从5.0开始呢定义的。然后呢,我们看看它有几种状态啊,首先这个叫new。就是我们所谓的这个叫新建是吧。然后这个呢叫able。这个呢,其实也不叫就绪,它相当于就绪和运行呢结合起来了。这个呢叫block阻塞,这个叫等是吧。啊,有指定时间的等待和。死亡。
43:00
哎,有这样的几个状态,跟我们刚才讲的呢,有点区别,但是呢,当大家呢,你要把这个事儿记住以后呢,我现在来跟你说它的一个对应关系啊,咱们直接看下边这个图。哎,看这个图就行。啊,一看呢,感觉有点绕,你先别管它中间这个方法的调用啊呃,新建还是咱们说的这个新建。哎,就是new啊,然后呢,我们刚才讲了一个叫就绪啊,其实也可以理解成呢叫准备,准备就绪跟运行这块就合在一起了,这个呢就称为呢叫runable了。就不再具体去分,你是准备好了还是正在运行呢,就不分那么细了啊,总之呢,你是一个可运行的状态。对吧,好,然后呢,我们所谓的这个阻塞呢,这时候你发现呢,它被分成了三种细细的状态了,一个呢,叫做blocked。咱们刚才说阻塞呢,其实就泛泛的说了哈,这块呢分成了一个呢叫blocked,一个呢叫waiting,一个呢叫time waiting分成了这样的三种状态,死亡呢还是那个死亡。
44:03
诶,所以这块你知道5.0之后呢,我们主要的体验点就是阻塞呢,分的更细了。诶因为呢,一些具体方法的调用呢,我们就把它分成是不同的情况了,比如说像我们刚才提到的说这个,诶叫失去同步锁,其实这块呢,涉及到的包括这个lock也类似哈,这块呢,其实如果。没有锁啦,我们称为呢叫阻塞。只有当你获得这个同步锁的时候呢,它才能够进入这个叫reno的状态。诶,把这个呢单独剥离出来,称为呢,叫做block的。那而我们刚才讲的这个wait啊,Wait呢,咱们提到了说wait呢,你要不写这个时间的话呢,这个就是阻塞,就得等待了,等待呢只能是被notify。而这种没有加时间呢,咱们就称为那叫无限等待。而你要是为这块加一个时间。是吧,那就是到这个时间的话呢,它就自动的就结束等待了,我们就称为呢,有指定时间的等待,那包括sleep这块,我们也会写个时间,所以呢,这个sleep呢得放到这儿。
45:03
哎,除此之外的话呢,还有其他的一些相关的一些操作,这个呢,咱们暂且就不在Java基础里边来讲了,这个呢就太多了,这个就以后的里边才会去讲的。好,所以这块呢,大家就先理解一下,相当于咱们刚才写的这里边儿的一些操作呢,把它们就分成了三种细致的,哎,三种状态了。啊,那如果说要是笔试当中问到说先生的生命周期是什么样的呢?诶建议呢,你这个呢,先记一下,记完之后呢,你给大家说的时候呢,你说这个。啊,就是新建randomable啊,然后死亡,这呢是最深最好说的这仨,然后呢,所谓的阻塞呢,分成了叫block的waiting和time waiting。哎,这样记一下就行。啊,所以说呢,哪些操作呢,会导致这个状态到另外一个状态,这个呢,就是随着我们后边的不断去使用,大家呢,熟悉一下就可以了。好,这呢我们说的线程的生命周期,这呢我又放了另外一个图,这个呢就是看这个方法呢,会更方便一些啊,你愿意看这个图的话呢,也可以OK。
我来说两句