00:00
好了,大家我们继续,那么刚才呢,我们使用这个JDK1.5以后出的这个lock同步锁解决了多延层的安全问题,那么接下来我们要考虑的是什么呢?就是说如何我们运用lock同步锁的这种方式完成一个叫做等待唤醒机制,对吧?也就是我们原来用single ne关键字的open类中的那个wait和notify完成的等待唤醒机制。那么我们说要完成等待唤醒机制最经典的一个案例,那就是什么呀?哎,对,那就是生产者和消费者案例,那么接下来呢,咱们再把这个生产者消费者案例呢回顾一下,顺便呢,给大家看另外一个问题,那么过来呢,我首先先建立一个类,对吧,比如说叫做test product and吧,And consumer对吧,Consumer,生产者和消费者案例,说生产者,生产者和消费者案例,那么我们说生产者和消费者案例,我们说生产者生产的产品,那是不是要给店员呢?那么反过来消费者是不是也得从店源处取产品呢?对吧?那么过来呢,我们说首先呢,我创建一个类,这叫做clerk,那么叫做店源,那么店员去干嘛呢?店员呢,它要维护它几个商品,我们搞一个。
01:28
Product p d CD,对,那么刚开始初始值为零,那么相应的那电源呢,其中有两个方法,一个叫做进货方法,对吧,我们就用这个,比如说叫做get代替一下,相应的呢,它也会有一个叫做卖货的方法,对吧?咱们就模拟一下,比如说叫做CE卖货,那么先说进货对吧?我们说呢,店员呢,它比如说最多呢,能有这个十个空位存储这个商品对吧?也就是说它最多呢能进十个货物对吧?再多了,那就是产品已满,无法添加对吧?那就来个if说如果呢,Product要是大于等于十,那就说明产品已满,那是不是就加不了了呀?那我就输出一句话,就说产品已满无法添加else,否则,那么否则说明个什么问题,否则那就是可以卖货对吧?那么在这里呢,我就打。
02:28
打印一个现成名对吧,点get name,拼上一个冒号,拼上一个冒号,然后呢,拼上一个,比如说加加product对吧,就是一次呢进。一个产品对吧,一次进一个产品,好,那这个进货呢,暂时先写到这儿对吧,咱们一步一步来,那么相应的下一个呢,那就是卖货,卖货呢,我们说那消费者如果来找店员买货,那么如果店员没有货物了,那是不是得告诉消费者那缺货呀,对吧?那得缺货,那就是if对吧?Product如果小于等于零,那么呢,就输出一句话,那就叫做缺货对吧,缺货那么相应的呢,Else,否则那么我们就也打印一个现成名点get name拼上一个冒号对吧?然后呢,打印一下减减pro,嗯,搞定吧,好了,那么暂时呢,我们说电员呢,先写到这个样对吧?那么我们考虑的是什么呢?说现在这个进货和卖货这两个方法,他们访问的操作的是不都。
03:47
都是这个共享数据product对吧,都是共享数据这个产品,那么也就是说这两个方法此时是不是都存在多线程安全问题啊,对吧?那么于是呢,我们可能解决这个多线程安全问题,那暂时咱们还是用single ne关键字,一会儿再给大家一步一步改,那么先用synchronize的关键字呢,修饰一下,因为他们访问的是共享数据,都存在多线程安全问题,好了,那么这个呢,就叫做电源,电源我们就写好了,暂时先写成这样,看看一会儿说不用送,不用这个等待唤醒机制,看看它会产生什么一个效果,什么问题,对吧。
04:34
好了,那么接下来呢,那我们就来个叫做生产者对吧?生产者生产者呢,我创建一个类叫做product,对吧?Product生产者,那我们说生产了产品,生产者生产产品,那是不是得给店员呢?对吧?那么呢,我们说这里来一个对象的关联,关联一个电源,然后呢,提供一个有参构造器,相应的我们说生产者呢,它有可能有多个,因此呢,我让他implementment一下runable,同时实现里边的run方法,那我说生产者做什么事呢?我们就在这里循环,循环循环几次,循环20次吧,对吧?循环20次对吧,让它不断的生产产品给这个clerk.get是不是给店员呢?对吧?那我们说生产者就写到这,那么相应的呢,下一个呢,就是消费者。
05:34
消费者和生产者那是不是很类似啊,Consumer也是employs对吧,实现这个叫做runable接口,相应的呢,消费者呢,也得买产品,是不是也得找这个店员呢,对吧?然后呢,我也提供一个有参构造器,然后呢实现这个。Round里边的run方法,那么我说消费者消费产品,那怎么消费,他也来一个for循环对吧,也来20次对吧,然后呢,不断的找店员买货,利用这个店员的卖货功能,这没问题吧,对吧?那我们说这就是我们的生产者消费者案例。
06:19
那么接下来我们就开始生产者消费者对吧?去一个去那个,不断的去这个进货,一个不断的去卖货,我们先看看它会产生一个什么样的问题,首先呢,我们说得有个电源对吧,叫做CRK,用一个CCRK对吧,首先要有一个电源,相应的呢,我们说那得有一个生产者product对吧,你有一个product对吧?那么他是不是得找这个店源呢?相应的呢,还得有个消费者对吧?那么consumer他是不是也得找这个店源呢?对吧?注意的是什么呢?注意的生产者和消费者此时访问的是不是共享数据啊,共享一个电源对吧?
07:07
那么接下来呢,我们启动这个线程点去start对吧,生产者我给它起一个名字,比如说叫做生产者对吧,生产者A对吧?相应的呢,我们说消费者呢,也给他来一个,比如说这个叫CS,这个呢叫做消费者对吧?那么这个时候我们启动,大家此时要注意的是什么呢?我们说现在呀,我们这个生产者消费者案例,那时候并没有使用等待唤醒机制啊,那么这个时候我们说看看它会产生一个什么样的问题,我们右键运行。对吧,注意看,那么这个时候呢,我们说一旦生产者发现产品已满了,他没有停,他还不断的生产产品,生产生产生产,是不是一定不断的去产品一满呢?现在呢,反过来消费者发现已经没有产品了,他还不断的去消费,不断的去不断的去不断去消费,对吧?那么之前我已经跟大家说了,之前有同学已经遇到过类似的这个面试题,对吧?那考官就问他说如果生产者消费者案例,他有可能产生一个什么样的问题。
08:24
对吧,那我们说现在怎么演示,课堂演示我们用的是这个生产者和消费者,那么实际上以后到这个实战当中,我们管添加和创建数据的线程,是不是叫做生产者线程啊,相应的反过来我们管删除和销毁数据的线程,那是不是叫消费者线程啊,对吧?那如果说生产者线程过快,也就是说你不断的发数据,不断的发数据另面另外一面实际上已经接收不到了,那么这个时候是不是可能就造成一个数据丢失的情况。
09:01
那么反过来我们说如果消费者过快的话,对吧,那我说不断的接收数据,不断的接收数据,但是呢,另外一面已经不发了,那这个时候是不是很有可能就出现重复的数据,或者说是错误的数据等等的这种问题。对吧,所以说呢,现在呢,我们生产者消费者案例对吧?如果不用等待唤醒机制的话,那么他就可能产生这样的问题,那么我们说如何解决呀,哎,对,那就是生产,呃,这个就是等待唤醒机制,对吧?也就是什么呢?说如果这里产品已满了,那么生产者还能再继续生产吗?那就不能了,那就得this点叫做wait,是不是就等待呀。对吧,然后来个踹开,那是不是等着消费者给他通知啊,对吧,那这个wait,那么相应的如果生产者成功生产了一个产品,说明是不是已经有这个多余的产品供供于销售啊,对吧?所以说呢,那如果成功生产了呢,那就this.notify哦,对吧,就通知另外一面可以卖货了,那么相应的咱们接下来再往下,我们说如果消费者发现缺货,他还能继续消费吗?那是不是也得给这块wait一下啊,同时来个try catch,相应的如果成功取走一个产品了,那就说明当前是不是这个店员的里有空位了呀,呃,对吧,有空位了,有空位就可以通知叫做生产者继续生产。
10:49
对吧,那这个就是我们所说的等待唤醒机制所解决的生产者消费者案例的这个问题,那么咱们右键运行,那么注意此时看现在的这里边是不是都是有效的数据了呀,对吧?说一旦发现产品已满,那么生产者就不会再继续生产了,对吧?那就是消费者在右键运行对吧?那现在此时里面的都是有效的数据。
11:19
那这个能有搞定吗?对吧,那这就是回顾了一下等待唤醒机制,那么接下来呀,大家注意,咱们呢,现在这个等待唤醒机制呢,它是稍稍有点问题的,说什么问题呢?咱们把这个呢,稍微的改一改,对吧?对吧,稍微的改一改,比如说我现在呢,给生产者这个线程,它是不是一共生产24啊,我给他搞0.2秒的延迟,来拉哥SLEEP200,我是不是来个200毫秒的延迟啊,我们以后呢,这些操作呢,都是在网络中进行,你有这个0.2秒的延迟,那是很正常的一个情况,对吧?那么呢,同时呢,我再改一个地方,我们说现在呢,电源处是不是一共有十个空位呀,我给它改小点,我就给它改成一个空位。
12:09
也就是说店员是不是只有一个空位呀,对吧,每次他只有这个,呃,生产者只生产一个对吧,然后消费者是不是也消费一个呀,然后他们俩来回的交替,是不是相对来说应该是比较和谐的一个情况,对吧?那这个也是正常现象啊,那么接下来呢,我把这个调成一之后,咱们右键再去运行的话,一直行。注意对吧,1010还是比较和谐的对吧,但是大家此时注意对吧,完事了完事了,但是发现什么呢?发现我这个程序它是不是并没有停止啊,对吧,并没有停止,我们说这是为什么呢?巧合吗?我们再来一次对吧,右键运行。那么我发现确实程序没停,说明我们写的有问题对吧,这个刚才我是不是就把这个产品调小了呀,然后呢,我们说生产者这里我多了一个0.2秒的一个延迟而已,对吧?那也就是说发现我们现在这个生产者消费者案例还是有问题,问题发生在哪呢?就发生在这个叫做get方法和cell方法的这个else这里。
13:23
对吧,我们说为什么发生这种情况呢?咱们举个模拟一下,比如说呢,我们说现在呢,可能这个我们生产者有0.2秒的延迟,那是不是消费者可能它速度快一点啊,对吧?那么接下来呢,我们就模拟模拟呢,比如说我们说我们是不是一共循环20次,按理来说程序是应该最后是停止了,但是呢,我们发现最后没停,对吧?那我们说比如说消费者现成对吧,他现在呢,循环还剩下最后一次,对吧?说循环的次数还剩下最后一次,而这个。
14:02
呃呃,这是消费者县城现在的生产者线程呢,循环次数呢,还剩下最后两次,也就剩剩下最后那么点,对吧,嗯。那么比如说这次呢,我们说开始运行,比如说被这个消费者现程获取到了这个资源,他是不是开始消费啊,那么比如说一进来开始消费,我们以product为零为例,票doct等于零为例,那么这个时候呢,我们说product小于等于零,那是不满足条件呢,满足条件一进来这里是不是就开始缺货,缺货了完后以后,那是不wait就等在这了,大家切记它是不是叫等在这个位置,同时释放所的资源呢?千万切记的一点是,当它被唤醒以后,它是不是在这个位置接下来往下继续去执行啊,对吧?那么好,那么我说当他这次循环进来以后,是不是wait在这,消费者先成wait在这里,那也就说它循环次数是不是已经剩零次没有了呀,没机会了。
15:12
那么这个时候product为零,这个时候呢,它wait了,同时释放了所得资源,这个时候生产者是不是线程就进来了,一进来它进行循环,还剩下一次对吧?一过来product大于等一不满足不满足是不是走else else,这里一运行打印名字是不是加加product呀,加加product它就变成了一,然后not five o对吧?然后呢,这个方法是不是结束出去对吧?那它是不是方法结束了,它也释放了所得资源呢?这个时候呢,也就意味着。叫做生产者和消费者是不是接下来同时抢锁了,同时抢锁,那么这个时候,比如说又被这个消费者现成。
16:00
哟,怎么被不小心被我关了,那么再打开啊,我们说这个时候呢,不小心呢,这个被我们这个消费者县城是不是又抢到了呀,那一旦抢到,他是从这个weight的地方继续往下执行吧,那一往从这里往下直行,那说else就不能直行了呀,不能直行。那消费者是不是就结束了,对吧,他循环已经没有了吧,那他消费者已经彻底结束了。消费者现场已经彻底结束,那么这个时候,那是不是就剩生产者一个了,他还有一次机会,那么比如说他这次一进来product刚才是不是正好等于一一等于一进来产品已满接过来。Wait,等待他,这一等待,还有人唤醒他吗?那不是没人唤醒了呀,没人唤醒我右键运行对吧,看看效果。对吧,没人唤醒他,那是不是就是造成了一个对吧,程序结束不了。
17:00
对吧,那这样的话呢,就产生了这个问题,对吧?就产生了这个问题对吧?看似没什么问题,但是呢,还是有很多问题存在,那么说如何解决这个问题,哎,那我们说把这个else去掉,是不是就能解决这个问题了呀?对吧?I说一旦去掉的话,那么刚才这个问题呢,我们就能解决了,对吧?怎么解决呢?比如说还是以这个为例,对吧,它是为零,然后它有二,对吧,那我说刚才呢,一旦这个消费者进来。是不是变零变零了以后对吧,然后呢,判断缺货wait是不是等在这啊,等在这下一次再运行的时候对吧?那么咱们再运行的时候,它是不是也从这开始往下,那比如说它就为在这了,为在这呢,这次呢,被生产者进来一判断大于等于一不满足是执行这啊执行这里的话加加product对吧,那时候product变为一。对吧,Product变为一,然后呢,这个时候它是不是就notty five o啊,唤醒所有,唤醒所有以后,那么这个时候呢,它在这里weight继续往下直行一直行减减,Product是不是又变为零了呀,对吧,刚才写多写一个啊,是不是又变为零了,对吧?一变为零再notice file是不是唤醒所有啊,这个时候它才结束吧,一结束,那这个时候呢。
18:25
这个呃,生产者又抢到一进来对吧,他是剩零次,然后一进来大,呃大于等于一,是不是也不满足,不满足又加加坡的。所以说这里呢,可能多操作几次,但是里边是不全都是有效数据呀,对吧,那么这一次呢,我再去右键运行的话。我们看看能不能顺利结束呢?那这次是不是就顺利结束了呀?对吧,那这就是解决了刚才那个等待了,被唤醒不了的一个问题,对吧,把else去掉即可,那么我们说把这个I虽然去掉了对吧,对吧,它还是存在问题,那么先说大家现在这个能理清吧,对吧,能理清就是最后呢,对吧,有一个等待了对吧,另外一个唤醒不了了。
19:19
嗯。好好,那么接下来呢,现在再往下看,我虽然说把这个I钥匙去掉了呀,它还是存在问题的,什么问题呢?我们现在呢,我是一个生产者和一个消费者,他们俩还是比较和谐的,说不是你就是我对吧,对吧,我等待你唤醒我,我我你等待我唤醒你对吧?那么两个还是比较和谐,那这次呢,我给他们多来几个,我搞四个四个县程,也就是说两个生产者县城,两个消费者县城。对吧,刚才是一个生产者一个消费者,现在是两个生产者两个消费者,那么同时去抢占资源,这个时候会发生什么问题?
20:05
对吧,咱们右键。运行注意看,不用再往下执行了吧,已经发现这都出负数了,负了这么多。对吧,那我说这是什么情况呢?我们说再过来,咱们再稍微的捋一下,我说现在两个生产者,两个消费者,也就是说两个生产者是不是都访问这啊,两个消费者是不是都访问这啊,那刚才说的负数多,那么比如说我们说一个消两个消费者同时来抢资源,对吧?一个进来,比如说product时等于零对吧,那么product小于等于零,一进来是不是缺货,为在这同时释放资源,这个时候呢,又被另外一个消费者抢到资源,Product对吧,小于等零是不是也缺货,也weight在这了。那么这个时候另外一面生产者对吧,来了一个noty在,哦,对吧,这个时候他们俩是不是同时唤醒啊,同时唤醒,同时都往下执行,是不是捡捡跑大,另外一个再来是不是也捡捡跑大。
21:09
对吧,那这就产生了问题,说这种问题称为什么呢?称之为叫做虚假唤醒对吧?那么这个时候呢,我们再看一眼API之前呢,我们说它留下了一句话,咱们没有读到的,咱们再把它完善一下,看这里O内容呢,Wait和notify或notify all吧,点进来看看这个wait方法,我们说少读一句什么看这说在某一个版本中对吧?某一个参数版本中中断和虚假唤醒是可能的。因此说,这个方法应该正式使用在循环中。如同这样。对吧,说你这个它是存在虚假唤醒问题的,那么他应该如果想解决这个问题,或者说我们这个wait方法是不是应该总是使用在循环中呢?
22:07
对吧,所以人家已经给我们考虑到了这个因素,所以说我们只需要按照人家的解决办法,是不是现在我们用的if啊,我们只需要把它变成while,相应的这个位也把它放到while中,让它下一次位置被唤醒之后,是不是再一次去判断一次啊,再来再一次去判断一次啊,那么这样的话我再去右键运行。注意看1010是不是比较和谐了,并且正确的结束了,对吧,再来一次右键运行。看看。搞定吧,好,那么这个呢,就是运用这个叫做等待唤醒机制,我们解决了一个叫做虚假唤醒的问题,我们说为了避免虚假唤醒问题,虚假唤醒问题对吧,应该总是使用在循环中才行。
23:10
搞定了对吧,咱们这是复习啊,那么通过这个呢,咱们呢,就把原来的这个叫做生产者消费者案例对吧,以及同步锁,以及等待唤醒机制,还有这个叫做虚假唤醒的问题,就做了一个完善的一个复习。考虑吧,对吧,好了,那么接下来呢,大家需要考虑的就是我们现在是不是用singleized关键字,用object类中的wait和notify对吧,完成的这个这个叫做等待唤醒机制啊,那么接下来我们说如何运用lock同步锁的方式完成一个。等待唤醒机制呢,对吧,好了,那么咱们这节课呢,先到这F10。
我来说两句