00:00
各位同学大家好,欢迎继续收看上硅谷GC高并发编程课程,刚才呢我们介绍到了可重入索,那下面呢给大家再介绍另外一种锁,这种锁是什么呢?我觉得各位同学应该都知道这种锁,它叫做死锁。所以我下面给各位同学就来介绍一下词所是什么,包括咱们用代码做演示,以及我们来说明一下这个词所到底该怎么进行验证。那下面咱就来说一下词所这个相关的内容,我这里边给各位来写一下。首先我们先看第一个内容,关于这个什么是。思索,或者说思索的基本概念到底是怎么样的?我在里边给大家解一下,那各位同学可以想一下啊,什么是死锁,死锁到底是怎么样的,我在里边给各位总结一下。
01:02
大家可以理解为我们现在呢,就是啊,有这么两个或者说呢,两个以上的这个进程。然后两个这个以上的这个进程怎么样呢?他们在这个执行过程中,因为呢,这个争夺资源的这么一个问题而造成的一种互相等待的这么一个现象,我把这句话写完,两个或者两个以上进程在执行过程中,因为这个就是。争夺这个资源而造成的这么一种互相等待的这么一个现象,这个就叫做我们说的词索,那这里边呢,如果说在这种情况下,它没有这个外力的这个干涉,那他们是很难再继续执行下去的,或者他们就无法再执行下去。
02:06
无法再执行这么一个下去。所以这个过程我们就叫做思索,这各位知道两个或两个以上线程,两个以上进程,他们在因为争夺资源造成的一种互相等待的现象,如果说没有外力的干涉,他们就无法再继续吞下去,这个过程就叫做思索。所以各位把这个给他要知道,然后这个词索呢,给各位同学我来画张图,咱们进一步来说明一下,我在这里边给大家画一下。比如说我现在啊,这里边假如说咱们目前呢,就是有这么两个这么两个线程啊,比如说有这个线程A,或者说线程B,那我们来写一下啊。这里边呢,我们写的叫这个线程A。
03:02
然后这里边我们叫做线程B,而这个时候呢,比如说我线程A中呢,它先持有这个所A,然后我现成B持有这个叫锁B,我在里边写一下,这个叫做这个锁A。然后这个叫做锁闭。现在有零八所,而我这过程中呢,就是我这个线程A它目前持有这个就是所A它是一个持有的状态。只有它这里啊,给它写出来。然后现在我这个线程B,它是持有这个锁闭。也是一个持有的这么一个状态,就是目前它获取到的这个锁币。而在这个过程中呢,比如现在啊,有这么一个操作,假如我现在我这个线程A想要去试图获取咱们这个锁B想要做这个操作,而我这个时候呢,我的线程B也要试图去获取这个锁A。
04:12
这个过程中呢,就会产生问题了,大家注意啊,比如说我现在线程A想要去呢,这个试图去获取这个锁币,那因为锁币。线程B是不是持有了,它是要等待线程B释放之后,是不是才能获取到,而同样的道理,我线程B比如现在想要试图去获取索A,因为索A线程A是不是你们持有了,所以他要等待线程A释放之后,线程B才能获取到索A。所以这就是我们说的这个互相等待的问题,因为他们互相等待,就是我等你,你等我,所以说这个时候如果说没有外力的干涉,他们就无法再进行执行下去,这就叫做思索,所以这个特点给各位来做一个说明,大家知道它的概念,包括这张图能给他看懂。
05:10
这是我们提到的什么叫词索一个最基本概念的一个说明。然后这个说完之后,我们继续往下来看,就是造成死锁,它里边呢有这么几个原因,也就是咱们通俗说的产生死锁有哪些原因,我把这个写一下咱们的第二问题。产生死锁的原因?那它有什么原因呢?咱们总结起来呢,产生死锁应该是有三大原因的,首先第一个原因,因为你的这个系统资源不足造成失锁,这是第一个,然后里边的第二个是什么呢?就是我现在啊这个进程,它运行过程中,它的推进的这个顺序是不合适的。
06:01
推进的顺序不合适,这个时候会造成思索。另外还有第三个原因是什么呢?就是你的资源分配。不当这时候会造成死锁,所以这就是产生死锁的三个原因,各位把这个给它知道,所以咱们现在就把这个死锁的基本概念给各位做了一个说明,大家知道什么叫死索,包括死锁产生的原因。然后这个说完之后呢,下面呢,咱就通过一段代码。给各位来写一个词索的这么一个例子,让大家进一步感受一下什么叫思索,那我这里边给各位来写一下啊,首先我这里边已经写好了一个类叫带lock,就思索嘛,然后里边有个问方法在里边我做操作,首先咱为了模拟出效果,我先创建这么两个对象,表示咱们的就是两个锁,比如一个A,一个B,那我来写一下啊,比如为了方便咱就来一个。
07:07
我来一个object,第一个我就叫这个就叫A。等于上一个object,然后我再来一个CI object。咱们来一个B,等于谬上一个object,代表咱们的A锁和B锁这两个,然后这个写完之后,下面呢,我在main方法中就来实现咱们刚才的这个过程,线成A,建成BA,持有所A,并且试图获取所B,然后B持有锁币试图获取锁A,咱们把这个过程来做个实现。首先我在里边先溜上一个thread。然后在threat里边呢,咱们加上这么一个S的关键字,我先持有这个索A,那我加上一个A,在这里边我把这个现成的名称咱们做个输出threat,点这个current threat.get name,然后后面我输出一句话,就是他目前呢已经持有这个。
08:17
所A。但是他目前要试图获取锁币啊,就是要试图去。获取这个锁闭,但是还没有获取到,这是我们的第一个,然后这里边我先把这个线程名称咱先写出来,这个线程,比如我就叫做A。然后点上一个。Start,这是我们的第一过程,然后写完之后在里边我再加上一个的关键字,咱们来一个B,然后这里边我写个输出,这个输出按照上面咱们给它快速改一下,这里我写一下啊,就是这个线程呢,目前是这里边它要获取到这个锁闭。
09:03
好在里边我们写一下就是。获取到这个锁币。这是持有锁A,试图获取锁B,然后这个代码中就是获取到这个锁B,所以现在咱们把里边的第一个过程完成了,完成之后呢,咱们用同样方式再写里边的另外一个地方,就是还是这个线程,但这里边需要改一下啊,首先咱是不是先持有所必应,这里边我就来一个B。这里我也改一下啊,持有锁B,然后他试图获取锁A,像这里边就是A,它就表示我们已经获取到了,所A跟上面正好相反。然后这里边的线程名称咱们改成B,所以大家看啊,现在咱们就快速把这个词索的这个代码做了一个编写。
10:02
然后大家看过程啊,我这里边是有锁A向获取锁B,这是获取到锁B,这是持有锁B获取锁A,然后获取到锁A,但是他们过程中。因为你要获取锁B,锁B是被他持有啊,而这里边你要取锁A,锁A是被他持有啊,所以他们目前就是一个互相等待的一个状态,这就是咱们快速编写了一个词索的一个代码。然后这个写完之后,下面呢,咱们把代码执行一下,我们看一下里边的效果是怎么样,咱们来执行。然后大家啊,看里边那个基本的这个特点啊,当然这过程中呢,咱为了更加明显,我在这里边呢,给他加上一个那个sleep,就让他看到更明确一点啊,咱给他完善一下啊。要不然我的线程创建是不确定的,得让他确定,给他加上一个sleep,就看到更明确啊,那我给他加上啊。比如这里边我加上一个叫time,这个呃,Time union,点上这个叫seconds,然后点上一个sleep,我们加上一个一让他这个一秒。
11:14
啊,这里边有个TRY开,咱给它直接加上。然后下面呢,把这句话我也给他加上。啊,加到这里,然后加上之后我们再来做个测试,看一下这个效果,就让它是一个能模拟出效果来。我们来执行,然后各位看效果,你看目前啊,我程序是没有停止,然后这里写呢,说A线程持有所A试图获取锁,B线程持有锁B试图获取锁A,但是它只是试图获取,还没有获取到吧,因为这个锁他们目前是一个线程互相等待的一个情况,他们就获取不到,他等他释放,他又等他释放,互相等待,所以目前这个思索的场景咱们就模拟出来了,就是里边的这个过程。
12:08
所以大家把这个代码给他,要能够快速写出来,比如说以后在面试中也好,在别的地方也好,比如说让你快速写一个词所代码,各位按照过程能把它写出来。然后这个我们就写完了啊,然后这个写完之后呢,咱们进一步给各位说明,因为大家注意啊,现在这个代码是由我写的,因为我是直接就按照我们的目的性,咱是不是就要写这个死锁代码票。而最终我们看到这程序没有停止,但是你注意啊,在实际的代码应用中,这个代码可能不是我们写的,但是我现在想验证一下,这个状况是一个死锁情况,因为各位知道这种情况咱们现在看的只是一种现象,这个现象可能不是思索,比如说我现在啊,这过程中。
13:00
我写了一个死循环,是不是也可能这种情况,或者说我做这个微服调用一直没调到它里边,是不是也可能这种情况,所以它不一定是死锁情况,那那下面要验证一下我这个代码到底是不是死锁的状况。这各位要知道啊,因为咱们是直接自己写的,我知道是思索,但是有时候可能我不知道他是不是思索,我需要做个验证来验证一下它到底是不是四索,那咱们就来验证一下,怎么验证呢?给各位来说一下啊,我在这里边写一下第三个就是。验证下。它是否是一个。思索,那怎么验证?这里边有多种方式,而我们这里边呢,咱们用两个命令来做验证,第一个命令叫GPS,这命令是什么呢?给各位说一下啊,不知道各位同学是否记得啊,在我们那个Linux操作系统中啊,其实它就类似于linu中的这么一个命令,叫做。
14:07
TS-EF。这个我应该知道啊,在Li中这个命令能查看到是不是当前的进程。而咱用GPS跟这个命令类似,能查看到当前正在运行那个进程,包括它的相关内容,这是GPS,然后除了这个之外,在里边咱可以用到里边的第二个命令,这命令叫做JS。TA,然后通过它呢,能够直接查看到里面那个堆栈的信息,或者说是跟踪我的堆栈信息的这么一个工具,这个工具是GM中自带的一个堆栈的跟踪工具,我写一下啊,GM里边自带的这么一种。堆栈的跟踪工具。
15:00
所以我们现在咱就用这两个命令,包括这个工具,最终来实现咱们这个词索的一个验证,那下面给个未来说一下啊,首先第一个我强调啊,这GPS呢,如果你要用的话,首先你需要做点事情,什么事情呢?第一个各位之前应该都配置过那个JDK的环境变量,然后这里边的这个GPS,其实在我们的JDK里边这个B目录下有一个叫GPS,大家找一下啊,比如咱们看一下GPS。我们看到啊。是不是就是里边的这个,所以咱们要做的话呢,你最好是把这个目录给它配置到环境变量的一个pass目录下,如果你不配置,每次还需要在并目录下这命令才能执行,这各位注意啊,就是最好配置环境变量,把这个目录放到你环境变量的并目录下,然后能使用,我现在已经配置过了,所以咱们直接来试一下,看它怎么做啊。首先第一个。
16:02
咱们打开这个命令行这个界面啊,就是这个命令行界面,然后在里边用个命令DPS-L,类似于咱们那个pef,然后咱们回车。大家看啊,这里边是不是有很多内容,然后在内容中大家看我们代码这个类的那个那种,咱们的类是不是叫带的log,是不是就这行,然后这里边是不是有一个号,就这个号列为就是我们当前运用那个进程号啊,当然还有其值就是咱说那PID。然后咱们叫6252,找到6252之后,我们用这么一个对战跟踪工具JSTCK,加上这个叫6252,然后咱们回车,咱们看它的效果是怎么样的。在我这个命令工具之行之后,最后面是不是行输出啊,告诉你什么B的一个这个带的lock,是不是发现了一个词索,所以当我们看到这里面证明咱的代码就是一个什么,是不是一个词索呀,这是一个词索,一个验证,然后咱们看他的信息中也告诉我们里面的过程,包括你看啊,他说发现一个Java这个级别,一个思索。
17:18
然后思考中他也告诉你了,大家看这个地方啊。V挺是不是等待lock是不锁,然后这个值叫428,这个叫438,然后你看过程啊,首先我们等待428释放,它已经锁住438,这里边是等待438释放,并且已经锁住了428,他们目前是不是一个互相等待的一个情况,所以在这里边给我们清楚的标注出来了,这就是他那个堆栈信息跟踪的工具,咱们通过这个工具加上GPS命令,就能够验证出我这个代码是否是一个词索的发生。所以咱们现在把这个。
18:01
死锁部分给各位做一个说明,要求各位同学啊掌握这么几点,第一个死锁的基本概念包括什么是死锁,死锁产生原因,然后第二个你能够手写一个死锁这么一个代码。第三个掌握词索这么一个验证的方式,包括咱们用GPS加上里面这个就是GM中自带的堆栈工跟踪工具,咱们最终做了这么一个验证,所以咱们现在就把词索过程给各位有最终演示出来了。
我来说两句