00:00
那接着呀,咱们来看一下这个j sta,它呢是用于打印GM中的这个线程快照,前面这块的话呢,我们讲这个jma,它打印的是我们这个堆空件的一个转存文件是吧?诶堆的一个转储快照,那通过这个解呢进行的分析,然后这个stack呢,是来打印这个线程的一个快照啊为什么叫stack呢?啊因为我们说呢,这个,呃,每一个线程是不是独立的拥有一个站是吧?那我们打印这个站的一个信息,洋外呢,我们就能够打印当前这个线程它执行的一个情况。啊是这样子的,好,那我们来看一下它的一个说明。来看下这个说明,说j stack啊,基于M呢stack trace啊,就是关于我们这个占空间的一个追踪,它呢是用于生成虚拟机指定的进程,当前时刻的线程快照。说线程快正好是当前虚拟机内指定的一个线程中,每一个线程正在执行的方法堆栈的一个集合啊,也是我们这个j stack的打印呢,会把这个进程当中的所有的这个线程呢,它的当前状态都会给啊追踪出来啊打印出来。
01:02
那么我们去生成这个线程快照的一个作用是什么啊,其实这块呢,说这个都有点多余似的啊,大家肯定清楚是吧,因为我们这个多线程在执行过程当中啊,有可能会出现长时间停顿的问题,多个线程争抢相同的这个资源同步的时候,那有的线程呢,就需要去等待这个同步加视器,对吧,这是一种等待,还有可能会这个等待这个远程的资源啊,包括呢,还有sleep,甚至还有死锁啊,还有这个死循环等等,那这些呢,都会导致我们这个现场一些不正常的情况。啊,会出现这个长时间的停顿,那我们呢,要想关注啊,说线程到底是哪段代码导致这个线程长时间停顿了啊,那这时候呢,我们就需要呢,可以用一下这个j stack这样的一个指令。啊,就是非常简单是吧,这个事儿,然后这个呃,大家如果想看官方的这个文档地址,你就把这个呃粘过来就行啊前面几个呢,我们也都是没有带大家呢呃去看是吧?啊因为这块呢,我都提前看过了,把这个内容呢,直接就整合在我们的这个课件当中啊是这样子的啊行,那么这里边呢,需要大家重点关注的呃,转储文件当中的几种状态呢,这个毫无疑问,咱们平时呢,大家学习这个多线程学习doc的时候呢,也是重点关注的这几种状态啊思索呀,等待这个资源呀,啊condition是吧?啊还有呢,等待这个同步健身器呀,啊阻塞状态呀等等,这呢是我们格外需要关注的。
02:25
哎,格外需要关注的啊,会导致我们这个县城呢,出现一些停顿对吧。好,那具体这个语法啊,具体这个语法啊,这个呢,也比较简单哈,直接呢,我们。哎,就直接在这输入一个j stack就行。哎,这就出来了,或者你这个输入一下接呃,Sta,然后杠H或者help写全了也可以行,那我们这个接sta呢,你看这里边提到了这样的几种用法是吧?啊,那你只要一看到这个,这就是连接远程的啊,这个我们就过了,然后呢,我们可以这个j stack后边加这个叫进ID,在进ID之前呢,可以填写这个叫option,这个option呢,可以有杠L啊,杠F,杠M,杠L是吧,还有呢,其他的一些执行语句等等的。
03:08
那这里边儿就提到了主要的这几个参数的问题啊,这一共四个是吧,哎,那对应的我们这块呢,就是这四个。啊,就是这四个,当然了,这几个参数呢,是可选择性的去添加的啊,没有说非得要加,所以呢,我们先来演示一下这个不加的一个情况啊,不加的一个情况,那为了来说明这个多线程的问题的,我这儿呢,提前了已经写好了几个代码了。因为呢,咱们讲解这个,诶GM这个课哈,诶大家应该知道咱们的重心呢,是使用这些工具如何去监控,那这个代码的话呢,为了模拟哎,咱们的相关的这个工具的一个使用是吧,一个场景,所以这块呢,代码是呃这个。特意啊,给他这个设置出来的,不是咱们整个讲解GM的这个重心了啊,咱不是讲解这不是重心,所以这个代码的话呢,呃,这个通常呢,大家会发现我课上就没有单独的再去一点点去敲了啊,不浪费这个时间啊,没必要啊,这个代码呢,都相对来说比较简单一些啊,当然呢,你设计这个代码实际上是比较讲究的啊,因为我们要想看到咱们相关的工具的一个效果,对吧。
04:09
好,这里呢,我是设置的是一个磁索问题啊,这个磁索呢,原理也非常简单,这呢造了一个线程,下边又造了个线程,让这两个线程呢,诶分别去握两个同步监视器,第一个线程呢,先握S1,再握S2啊第二个线程呢,是正好反过来,先握S2呢,后握S1。啊,这个应该很清楚是吧,那在他们两个互呃彼此呃这个先后去握这两个同步间然器的之间呢,加一个sleep,哎这儿呢,就很容易的是不是就造成这个死索啊,我们加上这个sleep的一个作用呢,是为了让这个死索呢,是不是出现的概率大大的增加是吧?哎,大大增加,你要不加这个sleep或者这个sleep的时候呢,哎,只能说这个出现的概率低了啊,哎出现概率会低一些。行,那我们把这个程序呢,直接给它run起来。好了,大家这时候呢,是不是就看到我们这个程序呢,就没有终止,其实呢,这就是一个思索问题啊,那但是呢,我们这个实际情况呢,可能这个代码量呢,非常的大,不像我们现在这个代码非常简单,你一眼就看出来这是思索了,那代码量比较大的时候呢,我们发现这个多个线程呢,长时间的没有结束,什么原因造成的,诶这时候呢,咱们是不是就可以进行一个分析了。
05:19
啊毫无疑问是吧,咱们就进行分析,那首先呢,GPS,那我们看一下当前这个进程啊,它的这个进程ID,然后下边呢,就接stack啊我们就幺幺,哎是不是476,哎把这个线程ID呢,往这一输入是不是就可以了,然后接着呢一回车。好了,这时候呢,我们就会看到呢,帮我们打印了当前这个县城的相关信息,那我们就往上找一找啊。哎,是不是在这儿了是吧?来接着往下看啊,这儿左边这个你看加这个双引号的,这都是我们当前程序当中的这个线程啊,都是这个线程啊,这呢是一个销毁的AGM的一个线程,它是一个reno的状态,它是正常的,然后这两个呢,诶,我们刚才程序中是这个匿名的方式,所以这呢,其实就我们刚才创建的两个线程,这两个线程大家可以发现他俩哥俩是不是现在是block的阻塞状态啊。
06:11
哎,那这呢,其实就不太正常了。那因为我们现在这个程序确实是出现阻塞了,对吧?啊,其实呢,就是他俩出现的问题啊,咱们先整体上先看看啊,还有呢,关于我们这个服务的线程renoable的这个C1啊,我们说这个编译器这个线程C编译器有好几个线程啊呃,C1的编译器的这是第四个啊,还有其他的这些是吧,这个你看好多哈啊,一共呢,是12344个编译器的线程啊,他们呢,都是这个reno的状态。啊,这呢是我们这个监视器的一个情况,还有呢,是这个线程,这个线程啊,还有我们垃圾回收的线程,诶垃圾回收线程,因为它是个守护线程啊,所以人家涉及到的这个叫微这这这都没关系,这是正常的啊。好了,那么到此为止的话呢,这涉及到一些垃圾回收的一些情况啊,到此为止的话呢,大家会发现咱们这个县城当中啊,除了你看到的守护线程这块,人家写的waiting之外,其他的这些你看都是reable。
07:07
当然了,还得排除就我们自己写的这两个,那基本上这个问题是不是就定位在我们自己写的这个程序这块有问题了,对吧,两个block,那最后呢,这个也帮我们其实做了一个分析啊,说呢,你这个程序当中啊,是会出现这个叫deadlock啊思索问题啊,这个线程一啊,你看他正在等这个monitor呢。啊,这个呢是呃,正在被这个4S杠零握着,那4S杠零这个线程呢,被4S杠一这个线程握着,哎,这呢,这不就构成了一个死索问题嘛,那下边就是我们对应的相相关这个代码的位置啊,就我们上面这个代码的这个操作啊,给你拿过来了是吧?行,那这呢就相当于我们通过这个JS stack呢就能定位啊确实呢是一个死锁的情况。哎,这就是这样子的啊好,这呢我们就把它呢关掉了,那我们还有其他的几个程序,比如这呢,有一个这个sleep啊非常简单,这呢是主线程啊输出一个语句,接着呢,哎,让他睡了,这是一秒,这是60秒是吧,呃,十分钟吧。
08:06
让他睡十分钟啊,那这个十分钟的过程当中,我们去执行这个j stack啊,把它跑起来。好了,这时候呢,打开看接接stack。啊,这个对应的是8440是吧。好,这时候我们做一个回车。行直接呢,就找咱们这个主线程啊。看这都是re的,这都没事啊,这都没事儿。哎,在这啊,这这个对着呢,这是这个呃,守护线程是吧,垃圾回收的线程啊,然后这儿呢,是不是咱们这个主线程啊,这个主线程呢,诶会看到我们现在这个没有终止,但是它这个waiting呢,还不是一个哎无限制的那个waiting,它这是一个time的waiting啊,因为咱们这呢,是不是让它SLEEP10分钟是吧?哎,这是这个原因造成的,所以通过这个呢,能够直接的分析出来,哎是哪个线程什么状态引起的啊,以及对应的操作是什么啊,都有显示好这个呢就过了啊,然后再来一个。
09:03
这个呢,我们来演示一下这个关于同步的问题。啊,这个题面本身呢也比较简单,嗯,这儿呢是一个run方法,里边呢有一个同步啊有一个同步,现在呢,我们是创建了两个线程啊,这两个线程呢,依次去打印这个数据,把这个数值number从一直打到打印到100,它们呢是一个同步的关系啊这呢一个同步加视器的问题是吧?好,这里边儿呢,我们是每打印一下的话呢,它在里边是这个500毫秒啊好,我们把这个呢抛起来。啊,大家看到就是这样一个效果是吧,行,那这时候呢,我们来过来GPS。接stack。对应的这个程序呢,是11992啊。好执行一下。好了,那这时候我们往前翻一翻啊,咱们现在呢,这里边两个线程呢,我给起名了,那这个叫线程一个叫线程二啊,直接呢,这不就定位到这儿了是吧,线程一线程二啊。那这个呢,你看叫blocked,这个呢叫time waiting。
10:01
诶这什么情况呢?那因为咱们不是让每一个睡,是不是500毫秒是吧,那这个正在睡着500毫秒的过程当中呢,而另外一个呢,是不是正在,哎,我们有一个同步加湿器啊,它正是一个阻塞的状态是吧?哎,所以这块呢,你看看的也比较清楚。啊也比较清楚,这呢,都是对应咱们县城这个state啊,它的状态啊。好,这呢,就是咱们说这个stack的一个使用。啊,带的给些使用,那应该算是比较清晰的是吧,好了,那接下来的话呢,我们看下这里边儿的几个基本的参数啊。几个基本的参数,这个参数呢叫杠F啊,这个F-F呢跟上面一样,就是false强制的意思啊,当正常输出的请求不被响应的时候呢,强制去输出啊,加一个杠F,呃,杠F呢,这个呢是除了堆栈外显示关于锁的附加信息,哎,关于锁的附加信息,这个咱们演示一下啊,这个杠M呢,就是如果你要调用到本地方法了。啊,就是native的这个方法啊,我们还可以显示一下这个C和C加加的一个对战杠help啊这几个里边呢,主要我们就看下这个杠L就行,对吧?哎,它就行啊,那杠L的话呢,那不妨我们把这个程序呢再给它跑起来吧。
11:13
把这个同步的跑起来了啊,然后在这儿,呃,咱们呢,GPS。啊接stack啊,然后呢,嗯加上嗯,咱们先整一个不加的吧。这呢叫13500是吧,哎,我把它写入到一个文件里了啊,比如说这个幺幺.t。然后接着呢,我在。注意在这个前面啊,杠L一下啊,我写到这个二二点。哎,这个T回撤一下,好,那一个呢是没加,一个是加了,我们看加的之后呢,是不是比没加呢要多一些信息啊,那这时候呢,咱们打开一下,哎或这个,诶宋洪康的这样的一个文件目录,这呢有个幺幺啊有个二二是吧,那这块呢,为了实现这个对比方便的话呢,咱们再用一个。
12:02
哎,讲。上篇啊,中篇的时候我们用过的一个工具是吧,这个我们叫做compare。打开好这呢,我们去选一下啊。在这里边找一下。这个。幺幺对吧。找一下二二。哎,可以了啊行,那右边这个呢。看一下咱们呢,是不是加这个杠L了啊,那加上这个杠L之后呢,相交于左边呢,你看多的东西呢,就帮我们呈现出来了,哎,这里边呢,就显示了我们出现这个哎这样的一个状态啊,锁锁住的这样一个状态的原因是什么啊,这也是我们这个参数大的一个意思啊,关于锁的一个附加信息啊,成这个呢,就是关于这个参数的一个说明。嗯,按说呢,我们至此为止呢,就算是结束了啊,最后呢,给大家稍微有一个补充啊,补充什么呢?诶,我这还写了一个代码叫做all stack trace啊。
13:01
这写个代码,呃,什么意思啊。就是在咱们这个thread这个类当中啊,这个thread类当中它有一个方法叫get all sta trees啊,获取我们所有的这个站的一个追踪信息啊,然后呢,这是返回来是一个map map中的key呢,就是我们一个一个的线程。啊,我们把这里边儿的每一个线程呢,取出来啊,然后呢,以及它对应的这个信息,我们也打印一下啊,在这儿呢,比如我们做个执行。啊,对于我们当前这个程序来讲呢,呃,它就列出来了当前这个程序这个进程当中的所有的这个线程的一个状态,对吧,那如果说呢,咱们不用刚才提到的这个这个j stack了,是吧,那我们Java层面有没有这个代码呢,能够稍微的也起到一些监控的作用呢,那就是我们这样的一个功能。啊,你比如说我把这个代码我CTRLC一下,比如针对咱们这个思索啊。哎,针对这个词索啊,那你看我们在这个位置。哎,比如说去new一个thread。哎,我们去一个有个thad.start一下。
14:03
哎,在这里边我们再传一个new一个able是吧?哎,回车一下CTRLV啊,把刚才这个代码呢,我们粘过来。呃,上面两个线程,这这三个线程其实都是在主线当中创建的啊,但是呢,我们,哎,为了让这个效果稍微好一点,主线程执行完,上面两个线程启动以后,让他俩先跑一会啊。咱们这儿呢,让他睡这个一秒钟。哎,然后呢,再执行我们当前这个,呃,追踪线程的这样一个问题啊,要不上边线程有可能还没创建呢,是吧,所以这块呢,让他稍微的阻塞一下啊好,那这个完事以后呢,我们直接呢去运行啊,哎,我直接去运行了。那那一秒钟之后,诶,大家能看到这里边的一些信息,大家看这些信息呢,是我们通过这个新建的一个线程调用的这些方法呢,执行的啊,这个方法其实非常简单啊,就是获取了一个all stares啊,这个就是追踪。
15:01
哎,当前。呃,这个进程中的。哎,所有的哎线程是吧,那那获取到这样map呢,我们只是做了一个哎for循环便利而已啊,所以这个呢,对大家来讲并不是难点。那我们看下这个结果啊,这呢就列举出来了一个一个的这个线程,那由于我们自己创建的这个线程呢,它比较晚,上面俩比较早也没起名,所以上面这俩线程一个叫TH杠一,一个呢叫杠零。杠零呢在这儿呢是吧?哎,然后我们这个执行这个输出的这个代码呢,就是S杠二了啊杠二了行,那你看这个杠一这里边呢,它执行到这行代码63的时候。真到63的时候呢,这行停到停到这儿了。啊,停到这儿了,你看它为啥停到这儿呢,这是我们这个呃,相当于第二个线程哈,它是握住外边这个锁,握里边这个时候呢,停了,那正好相反的,就是我们下边这个杠一呃杠零。那在这点它是不是握住上边这个同步监然器的时候,握下边这个呢,听了是吧,哎,通过这儿呢,也能够看出来,这是一个死锁的问题。
16:08
啊,是这样子的,当然了,诶我们从这个信息上来看的话呢,是不是还是不如我们这个这个j stack更智能一些,它直接就告诉我们说,呃,出现这个思索问题了啊,像刚才我们这个看这个数据的时候是吧?呃直接就告诉咱有思索啊,具体在哪那说的还比较清楚,比咱这个靠谱一点啊。行。那这里的话呢,咱们就把这个J呢就说清楚了,总结一下。总结一下啊,就是如果呢,大家在程序执行过程当中,出现了这个线程的这个停顿时间比较长,那你就用这个j sta呢,你去呃查看一下,你看是不是出现了相关的这样的一些线程之间的问题啊,以及呢,对应的代码是在哪一行啊就可以了啊,这就我们说的这个接磁带。
我来说两句