00:01
各位同学大家好,刚才呢,咱们通过这个S的关键字完成了线程间通信的代码,最终实现效果就是两个线程,一个加一,一个减一,让他们交替实现多次,这个效果咱们目前已经做到了,通过这个效果,大家重点掌握多线程里面这个编程的步骤,第一步,第二步,还有第三步,那我下面呢给大家演示一下在咱们做这个线程间通信中可能会产生的一个问题。那问题是什么?给各位来说一下,大家注意啊,我刚才是不是有两个线程,比如我现在啊,往里边咱们一共加入四个线程,那我现在把这两线程我再复制一份。然后给它改个名字,这个名字我们叫这个CC,然后这个叫BD,比如说我想实现AA是一,BB是零,CC是一,BB是零,咱们用四个线程做到,就最终变成A是101010,然后CCDD也是1010,这个效果咱们最终看一下我们加上四个线程之后,这效果到底对不对,比如说你看啊。
01:19
AABBCCBB,然后A和CC里边都是做这个加一操作,BB跟DD中都是做这个简易操作,那我现在把这代码执行一下。咱们看一下什么效果,大家注意啊,效果好像不对吧,正常应该是1010到这里都对,但是后面就不对了,你看变成多少,是不是有234567等等不同的值,比如说咱们可以再执行一次,比如这个我先关掉啊,咱们再进行一次。然后大家看里边还出现什么,是不是还有这个负值的效果呀,所以这个肯定不是我们想要一个结果,正常应该是一零运行效果,那这效果为什么会有这个问题呢?下面给大家来解释一下啊,首先咱们看代码中。
02:13
其实大家会发现代码里边咱们是不是都做了判断呀,如果说我的判断能生效,是不是应该不会出现负一或者大于一的值,比如说目前问题大家应该能看到,应该是这个判断的过程出现了问题,那它为什么会有问题,咱们看一下这个A片文档中,首先大家看啊,当我的判断条件,比如说我的值不等于零,在这不是等待,当它值不等于一,咱是不是也用wait等待,所以咱就看一下这个weight方法里边,它里边有一段话,也就是这段话。这段话呢,清楚的告诉我们他为什么会有这个问题,那我们来读一遍啊,这里写到。对于某一个参数的版本,实现中断和虚假唤醒是有可能的,而且此方法应使用在循环中使用,那这什么意思呢?也就是说目前的问题它就叫做虚假唤醒问题,这是咱看到的,它是定个问题叫做虚假换境问题,然后他也告诉我们了,咱们需要把这方法始终写在循环中使用,也就说你看里边是不是加Y,比如说咱们写这个条件判断需要加到while中进行实现,而加到一中它就会有刚才的问题,这些问题就叫虚假唤醒问题。那问题具体是怎么产生的呢?下面给大家我来分析一下。
03:40
然后我在这张图上给各位来画一下。大家看一下啊,首先咱们目前是不是有四个线程就是AA啊,我写一下第一个A,第二个BB。第三个CCD,四个我们叫BD,咱们目前有四个线程,而四个线程要实现的效果就是。
04:03
AA线程是不是要加一,然后BB线程要怎么样减一?CC是要加一,BD是不是还是减一,咱们应该是做这个效果,当然过程中为什么会有刚才问题呢?给大家说明一下啊,因为咱们说到abbc是DD,它们都是掉了大的方法进行相应创建,但是谁先谁后不一定吧,可能先AA,也可能先DD。所以咱们说明,比如说我现在啊,就是我一进行操作,AA线程先创建了,那A线程创建之后,它首先把这值是不是要加一啊,最终结果就变成了一,这是第一次,而它创建之后,这里边是不是最终在通知加线程,比如说大家看代码中就是这一行的体积,首先第一次肯定判断没有问题,然后这个位置加一,加一之后load by o再知加线程。
05:04
而他在通知C线程中,可能是BB抢到了,可能CC,也可能DB,比如现在哈,恰巧这个BB线程,或者说CC线程抢到,咱说CC。那CC抢了之后发现这个值是不是一呀,那一的值它是不是就不会加一,所以它要怎么样,是不是做一个等待的这个效果,因为它要加一嘛,也就是这行代码中,当看到它不是零,是不是等待,而它等待之后干什么?这里边是不是其他线程再去抢东西,因为咱说过weight特点就是会释放锁,它一释放别的线程就能抢到那种,所以这里边它会进行等待,那别的线程进行抢,那比如现在啊,假如现在这过程中CC已释放ABABDD是不是都有可能抢到这个资源,比如说现在恰巧这个A它又抢到了。
06:03
当然各位注意啊,A抢到之后,它是不是应该做加一啊,但是目前的值是不是就是一啊,正常效果就是它的值应该是直接等待,但是里边啊这位置,比如说他现在到底里边A里边强调了他发现值不是一,那它怎么样是不是进行等待呀,所以他现在A这过程中,我们就进行这个等待操作,而他在等待的时候,其他线程是不是并am来抢,那他在抢的时候大家注意啊,比如我现在这过程中。BB正好抢到了,那BB抢到之后它的值是不是要对它做一个简易操作呀?啊以此类推,应该咱们正常是这么一个效果。这各位应该能理解啊,就是我比如说a abbc DD AA和CC判断值是零就加一,然后CBB和DD判断,如果值是一,那它就减一,正常应该是这个效果,但是这过程中呢,因为咱们是多个线程,所以这过程中可能会有咱刚才说的问题,那我下面说一个就是不是正常执行的效果,那什么效果呢?比如现在同样AA把这个强调了。
07:17
一次是一,然后它是一之后,那这值它是不是要加一啊,它的值就变成了一,然后变成一之后呢,这个时候它要通知加线程,比如他现在啊通知这个CC线程,那CC线程目前是不是一个等待状态,比如说CC线程它就在这一行做了一个等待,然后他等待之后别的线程要进行这么一个就是切换操作,比如现在操作过程中,恰巧这个AA这个线程他又抢到了,然后他抢之后发现不是他做的事情,是不是还要去通知其线程,比如在通知时候呢,恰巧CC又抢到了,当然各位注意啊,CC在抢到的时候呢,里边有这个特点。
08:00
它里面是不是在这行已经睡觉了,然后他在睡的过程中被别人把它唤醒了,而wait方法有一个特点,什么特点我写一下啊,它就是在哪里睡。那他又会在哪里醒,这是特点,比如说CC之前在这一行睡着了,但是目前他在这一行被唤醒了,那他怎么做,他是不是就继续往下执行,比如说你之前的判断就不生效了,他只判断了第一次,后面他在醒来的时候,那这个等待它里边就直接往下执行了,你的判断就没有生效,这就叫做虚假唤醒问题,也就是说到通俗点。咱们这个写亦不判断,只会判断第一次等你,后面这行一等待,那他后面就是在哪里睡就在哪里醒,那这行它就会继续往下执行,前面的义负判断就不会生效了,所以会造成我们的结果就是要么出现大于一的情况,要么出现小于零的情况,这就叫虚假唤醒问题。
09:12
所以这问题我们怎么解决呢?把这判断写到一个Y循环中,Y循环不管你在什么时候睡,什么时候醒,都要经过咱们这个判断的条件,所以这就是我们的解决方案,所以大家把这知道啊,就是正常效果,就是它是等待,然后这里边做判断,但是因为咱们加了if if里边用wait方法,Wait方法特点就是在哪里睡就在哪里醒,所以咱们一醒来之后,他的if就不生效了,他就直接往下执行,而加上will well之后,他不管在什么时候醒,前面的条件都会进行知晓。所以现在啊,是咱们说的这个解决方案,那我给它加上Y之后,咱们把代码再执行一下,大家看目前效果是不是就正确了,ABB CC DD分别实现加一减一,加一减一的各种效果。
10:12
这个就是咱们说明这个就是虚假幻境问题,所以各位写的时候注意这个特点,需要把这个条件判断放到while中,要不然这判断就为执行一次,后面就是直接往下执行了。如果这个过程呢,各位还不理解,给大家再举个比较现实中的例子来说明,什么例子呢?各位应该知道啊,各位同学应该都坐过飞机,就算没坐过飞机,应该看过别人坐过飞机。而咱们坐飞机的时候,应该都会做件事情,叫做安检。那给大家用这个例子来说明一下什么叫虚假唤醒,那我强调啊,比如说你现在啊,坐飞机经过了安检,然后到了飞机上,那这个时候呢,飞机正要起飞,这个时候呢,你突然听到那个叫机长广播,因为机长广播肯定是有重大事件发生,这时候广播说到说现在飞机上呢,发现了有这个可疑的物品,需要所有人下飞机进行检查,那你注意这时候你们这些人是不是要下飞机,有,那我问各位啊,比如现在这个安检,检查之后发现飞机上是有人恶作剧,没有什么可疑物品,那这个时候所有人是不是需要再上飞机呀?那我问各位,你要再上飞机还需要再进行安检吗?
11:37
还需要吗?答案是肯定的,是肯定还需要安检,只要你下了飞机再上飞机,安检必须要进行,如果你不进行,比如这时候你看飞机拿了一些无机物品,那肯定是不可以的。所以这就是我们说的虚假唤醒问题,你下飞机之后还需要再次进行安检,如果说你不安检,那就会有这个虚假幻境问题啊,这就是我们解释这个安检的例子,通过它也能说明这个问题。
12:09
所以最终各位记住它的结论,咱们这个条件判断的这个部分需要放到while循环中,要不然会产生虚假唤醒的这么一个问题。所以这个我们给各位做了一个说明,大家把这个给他知道。也就是说这个就是咱们编程步骤中等,就是它的下部,所以咱现在把上中下三部应该都说到了啊,它的下部是什么?比如咱们说的第四步。我们就是。防止这个虚假唤醒的这个问题,咱们把条件需要加到我们这个while循环中。所以现在这问题给各位就最终演示出来了。
我来说两句