00:00
那接着的话呢,我们关于线程通讯呢,其实就说完了,说完以后呢,在多线程这块呢,有一个比较经典的问题,经典的问题呢,就是叫生产者消费者的问题。哎,就是一谈到这个多线程这块呢,通常大家如果写一个稍微经典的问题呢,都爱写这个题,所以咱们这块呢,把这个题目呢,也给大家讲一下啊,这道题呢,同时也把咱们这一章前面讲到的这个知识点呢,也都这个集合在一起了,属于一个综合性的问题,看一看,生产者叫product,生产者呢,将产品交给店员叫lirk,这个消费者呢叫customer customer或者你叫consumer是吧,消费者都可以啊,说这个消费者呢,从店员这块呢取走产品。店员一次呢,只能维持固定数量的产品,因为它这个呢,柜台有限,比如说呢,维持20个,那如果生产者试图生产更多的产品,这个店员呢,会叫他停一下。
01:03
也就是说呢,生产者他只有一个事,就是生产产品,让我们这个产品的这个数量呢,不断的去增加,但是呢,如果超过20的时候呢,我就会让他wait一下。啊,那如果有空位了,就是不足20的时候呢,我就通知他呢,你可以继续生产。那这是这个,那如果说已经没有产品了,都已经产品是零了,这时候我们会告诉消费者呢,说你也等一下,就是你这时候呢,你wait一下这时候没有了。啊,那如果要是有的话呢,哎,我就哎把你唤醒,你就接着可以再去消费了。啊,这里边就会涉及到一个通信的情况啊,那下边呢,就提到这有这样的一些这个问题,这呢也会涉及到一些所谓的安全问题了啊,包括呢一些通信的问题,诶那么我们下边呢,就来写一下这道题目啊。嗯,这个题目咱们就写到这吧,新建一个Java class,嗯,这个关于我们这个叫产品啊,我就写个叫product的一个测试了。
02:05
呃,经典的生产者消费者问题。哎,这呢,也相当于咱们叫线程通信的一个应用。哎,生产者消费者问题,具体来讲,咱们呢,就拿这样的一个场景来说。嗯,好,来说明一下这个情况,嗯,咱们首先还是啊这个题目稍微大一点,我们就来分析一下,首先分析第一个问题,是否是多线程的问题,哎,这个是是吧,那既然是的话呢,那这里边的多个线程是什么呢?哎,是不是有这个生产者的现场,消费者的现场。嗯,至少得有俩。
03:00
一个生产者,一个消费者,当然了,你也可以更多啊,比如说两个生产者,一个消费者,哎等等都可以,至少得有两个,这是第一个,那既然是多线程的问题,下边一个紧接着要考虑的是是否有线程安全问题。是否有现场安全问题,又依赖于是否有共享数据的问题。是否有有。啊,既然有好共享数据是谁啊对,有同学说是店员,有的说是产品,哎都笑了哈,其实是对的,哎,就是你生产者消费者,呃,我生产的东西了,我是不是交给了也是店员是吧?哎,你消费者呢,也是给了店员,其实这时候店员呢,也是一个共享的。啊啊,那是是呢,话是谁呢?呃,你可以说这个叫店员啊,或者呢,你说是这个产品产品或者叫产品的数量啊等等都行啊好,那既然呢有共享数据,这时候呢,你就要考虑呃去处理这个呃现场的安全问题了。
04:05
啊,处理这个线程安全问题,那处理线程安全问题,我们就考虑说,呃,这个叫什么呀?呃如何来解决呃解决呃线程的安全问题啊这个呢,咱们就使用这个叫同步机制,哎有三种方法。那三种方法啊,好,这个事儿呢就完事了,然后再接下来解决了限制安全问题呢,其实就已经挺好了,至少呢不会出错了啊,但是呢,还有其他的问题,这里边呢,涉及到他们的一个通信。嗯,怎么算叫通信呢?这个生产者的话呢,你要是发现这个产品数量超过20了,这时候你就得wait一下。啊,那对于这个消费者来讲的话呢,这个人家这里已经都没有产品了,这时候你也得wait一下,哎,当代有的时候呢,你再去这个唤醒是吧,这呢,哎就泛泛的写一下,说是否涉及到线上的通信。
05:05
哎,这个呢,显然我们说是,哎,那既然需要涉及到线程通信了,那你就得要用到那个wait和notify,哎这样的功能啊,那基本上把咱们前面涉及到的一些知识点呢,就都串到一起了,多线程的创建,哎同步的一个解决,然后呢线程的通信。好,那下面呢,咱们来看看这道题目呢,该怎么去设计解决它啊。嗯,该怎么去解决,首先呢,涉及到这样的几个结构,咱们都应该把它们是不是当做一个类来处理啊啊呃,首先咱们可以先整一个电源吧,哎,RK这个啊,然后接下来哎,Class可以去整,这个叫生产者是吧,普。Producer吧。啊,Product product是产品,Produce是生产,我这叫product producer也行啊。
06:01
丢是or还是ER?应该是应该这个对着的啊。查一查这个,这个有道。Pro。啊,这个没有网是吧。应该是一吧,啊,我就写成这个啊叫producer,你用这个produce也行啊,嗯,R那它是线程了,那就涉及到我应该用继承还是用实现。对吧,继承实现都行。都可以啊,主要呢,就是你后边处理这个安全问题的时候呢,嗯,你考虑一下那个同步监视器得保证是唯一的啊,这个呢,比如我再演示一下这个集成吧。好。咱们这呢,因为也没有显示的负类了,所以我这集成thad没事儿,你要有显示负类的,那只能是实现了,嗯,这是它,嗯,因为呢,这是一个生产者,消费者呢,都共用这个CRK了,所以我在这里边跟咱们讲前面那个练习题一样啊,咱们去声明private crk类型的这个变量,然后构造器auto shift s。
07:21
诶,我去呢,调这个浮力的空餐,把这个可乐可呢给它放进去,诶这么着去处理。这个呢,是生产者接着消费者。Class消费者叫consume。啊,Consumer这样啊,让他呢去我也用这个继承了。就是你要用继承,在这一道问题中,你就都用继承实现了,就都实现,你别这个继承,这个实现整的怪怪的啊,这呢是消费者,我呢处理方式跟咱们这个生产者一样,哎,这么着去争。哎,这么着,这个逻辑目前都清晰是吧?啊那么回头呢,咱们在这个代码测试当中,哎这样做咱们呢,去造一个这个RK电源。
08:11
诶,然后呢,我们再去new,具体的这个叫诶producer这个属于这个叫生产者,把我们这个可可给它扔进去,哎,Al enter,哎,我们造了一个叫PE吧,哎,然后呢,给它呢起个名字。哎,这个呢,我们叫生产者一。对生产者一,然后接着呢,你再去造一个消费者。哎,接着呢,这个C一点赛一个name,消费者一好有了两个线程,诶,你接着让这个P一点,我们去start。哎,叫这个C一点均start,这又跑起来了,跑起来呢就会执行我们各自线程当中的run方法,这呢没有写,哎加个软。
09:10
删掉,然后这个呢,也是加个RA。看下边的重心就是来写你这个线程各自的转方法,对于我们这个生产者来讲,他做的事儿就是一顿生产,所以上来我们可以先简单写个输出语句啊,说叫生产者生生产生产者谁吧,生产者谁呢?就涉及到你这里边这个名了嘛,那咱们这个位置你就可以thread.current thread.get一下name呗。或者我们现在是继承的方式,这个位置不也可以省略掉吗?哎,说。哎,这个冒号,哎叫开始生。开始生产这个产品,诶这时候呢,他就开始生产这个产品了啊,开始生产产品对于他来讲,嗯,没有什么限制,你就一顿生产就完了,所以我们可以写成一个while里边呢,整一个处,诶他做的事呢,就是一顿生产。
10:11
一顿生产,那具体的生产咱们是不是就可以,诶让调一下我们这个RK里边,呃,这样的一个,我们让他比如说去produce这个product。就像咱们那会儿讲的这个客户里边有一个账户,让账户这块呢去调那个,呃存钱的方法一样,哎咱们就这样去调,没有这个方法,Al一下创建一下,哎在上边,哎这呢去生产,呃它没有什么限制,就一顿生产就完了,呃你要说唯一想加上一个这个这个点呢,你可以让这呢稍微的慢一点是吧,诶慢点去生产就可以了。行,这呢是对咱们这个叫生产者的要求啊,就是你就你就说它生产外处生产就完了啊,那么对于咱们这个消费者来讲,跟这个逻辑呢,类似CTRLC,我们就在这里边粘过来啊,这是它呢开始消费。
11:11
产品那那这呢,我们就不能调这个了,消费呢叫consume product,没有al enter,去造一个al enter,哎造个这个方法。行,那关于这两个run方法,其实也就写差不多了,下面的重心就回到我们这个,可这块可乐这块呢,两个方法,第一个叫生产这个产品。哎,生产产品,这呢叫消费产品。哎,生产产品消费产品好,生产消费这个呢,我们里边涉及到这个产品了,你这还没有啊,具体这个产品是什么,咱们就不不去造一个类来表示这个产品了,哎,咱们这就专门只是体现一下这个数量上啊,这个得是一个限制安全的,所以我这呢就定一个叫private int型的,叫呃,Product,呃,叫number吧,或者叫count也行。
12:13
数量啊,诶这呢,一开始是零,一开始呢一个产品也没有,然后呢,我们生产产品就让这个数量去加加,消费产品让这个数减减。嗯,就这么着就行了,好一个一个来写,首先呢,去生产。嗯,他去生产,那我们得判断一下,因为咱们不是有限制吗?说如果你这个产品的数量啊,小于等于不能要吧。20的时候就就不要生产了,是吧?哎,当你小于20的时候,我们就去生产生产,我这样写,嗯,说谁谁谁开始生产产品了,这个我们加一个。thread.current thread.get name,哎说比如说这叫生产者一,嗯,这个冒号开始生产。
13:11
开始生产什么呢?生产开始生产第几个产品?第几个呢,我就用这个product count。嗯,生产第几个产品。那我这呢,得先怎么着啊。产品,嗯,你要这样写的话呢,这个咱们要是零进来,那就成了开始生产第零个产品了,是吧,加加一下吧,先加加了。嗯,先加加,这时候呢,就开始生产第一个产品,嗯,开始对呗,如果这时候呢,这个product是19,那就已经有19个产品了,呃,19小于它,然后先加加20,生产第20个产品,如果已经有20个了,这个进不去。
14:04
嗯,也不加价,就这样行是吧,这呢是咱们这个小于20,就是已经是这个,呃,这个不足20个的时候呢,去生产,那要是满足超过或者就达到20个的时候呢,对超完时候,这时候他就不要生产了,其实我们是不是就想写位了,但这时候你就位呢,其实还写不了。也没涉及到同步呢,还是吧,所以暂时呢,咱们可以先放一下啊,先放一下,接着呢说下边这个叫消费产品,消费的话呢,也是要判断,如果我们当前的product count能消费的前提呢,是你得大于零,不用等于是吧,等于你也消费不了了,嗯,先out一下。说thread.current th.get一下name冒号。嗯,叫开始消费第几个产品。
15:00
消费的话呢,他是先消费呗。开始消费。D这个。各产品。嗯,对于这个,呃,消费的话呢,是先消费了,然后呢,我们再减减。这个呢得稍微留意一下,比如说呢,人家就只有一个,哎,那就是product是一的时候,哎,他消费的第一个产品,然后这时候呢,减减一下。哎,这个呢是先加加后输出,这个是先输出后减减啊,这要稍微注意一下,嗯,那么else else呢,就意味着你当前的这个产品数量呢,是等于或者是小于零了,哎,那就没有了,这时候你需要呢,也是啊等待,哎这个呢也是等待。好,这呢,就是这样一个问题。
16:01
啊这样问题,那基本上这个大框架呢,我们就搭起来了啊就搭建起来了,搭建起来的话呢,我们往下顺哈,说这里边呢,共享数据,共享数据呢,说有那就是电源或者说呢,叫这个产品的数量了,哎这是共享数据,那既然有共享数据,大家都来操作一个线程呢,操作它一个线程来操作它,那么就有可能上面这个线程呢,我正在判断执行的时候,我这个已经加加了,比如我这个加加完以后呢,我这是呃第十个产品嘛,相当于我生产了第十个产品,那按说呢,我这马上就得说我生产了第十个产品,但有可能在这两个之间呢,是不是阻塞了,哎,我这要一阻塞马上呢,这个下边呢就开始消费了,我刚生产完这个十,你下边呢,就咔消费了一个。结果导致我这块呢,明明生产的是第十个产品,这携程了说开始生产第九个产品了,这不就会出现这个线程安全问题了吗。嗯,因为咱们下边这个方法,另外一个线程呢,也在操作product count。
17:02
啊,那为了保证这个操作和这个操作涉及到的共享数据呢,在一个时间段之内呢,只能有一个线程去做,咱们得处理这个线程安全问题。那这两个方法,你你又不可能说把这两个整个包到一个同步代码块当中,那那语法上哪能这样做呢?哎,怎么办呢?是把这两个方法给大家同步一下就行了,因为正好这里边这不也是完全的操作共享数据的代码吗?诶,所以我们这么着一下就可以了。能理解不?嗯,那就意味着呢,看咱们下边呢,这不这是一个线程,这是一个线程,然后呢,两个线程,上边线程呢,执行的是produce,下边呢执行的是consume,那就意味着呢,当我们比如说这个生产者啊,比如我们这个生产者呢,我这个此时呢,在这个西寨这块呢,我要握着这个同步监视器了,此时的同步监视器是谁呀?
18:09
是不是他的对象啊,对吧?哎,那这个对象咱们自始至终这不就造了一个嘛,就造呃在最后这啊这咱们就造了一个,说明他是唯一的啊,这个没问题,那当我们这个生产者呢,他呢,这个握住这个同步加湿器以后呢,他进去了,这时候呢,你的生产者,呃,你的这个消费者还能进去不。就进不去了,因为你的这个同步监然器是不是也是这次啊,那我们这个生产者在里边去操作,即使呢,你在里边有sleep呀等等啊,哎,这个别的县城你这块呢,虽然是sleep了,但是这个县城呢也照样进不去,只有当我们把这个产品都生产出来以后,诶你呢,才有可能抢到这个头步健身器,你再去消费,这样这不就安全了吗?啊,就安全了啊,那这个生产这个消费,呃,加了这个同步以后,咱们这个weight呢,这不就也可以去加进去了,呃,因为它只能够使用在我们这个同步代码框或同步方法当中,Al enter处理一下这个异常,哎,我们try catch一下啊,哎下边呢也一样。
19:15
Al enter一下,而且呢,这个时候我还可以比较大胆的,就是没有写前面对象点了。因为正好是不是也是Z4啊,哎,就省略了。行,这时候呢,我们加上wait了。嗯,只要有是不是你得考虑那个notify。嗯,对,暂时呢,咱们假设就没有加啊,没有加的话呢,我们看一看什么效果呢,跑一下。哎,这时候你看这个生产者,生产者开始生产产品,消费者开始消费产品,生产者就开始一顿生产,生产到这的时候呢,他喂了这个消费者的话呢。消费者在这儿。
20:00
哎,这个为什么会出现这样的情况呢?说消费者一下也没有是吧。实际上呢,是因为这个时候的消费者呢,哎,这个生产者开始生产,消费者开始消费,马上这个消费者呢,他就去消费了,他去消费的时候发现没有嘛,没有他就wait了。嗯,所以呢,这时候你没有看到这个消费者消费一个产品,因为上来就wait了。呃,然后生产呢,就一顿生产,生产到这个20的时候呢,达到这个极限了,它也就wait了。哎,就成这个样子了啊,哎,那这块呢显然不行,呃,咱们呢,需要去加这个notify的逻辑啊,好看一下这notify加到哪,比如说。嗯,比如说就咱们这个问题吧,这个问题的话呢,这不是相当于一上来这个消费者呢,这时候就给,诶就给wait了,因为他消费者一上来想消费发现就没有,这时候他就给注册了,然后对于我们这个生产者来讲,生产者的话呢,只要我们生产了一个产品,我是不是就可以去唤醒那个消费者了,哎,所以我们在这个逻辑里边,诶是不是可以去加上一个叫notify。
21:07
哎,就可以去唤醒,诶你对面的那个消费者了,那么对于消费者这块也一样啊,人家这个生产者呢,如果说一顿生产,生产到20个的时候呢,他就wait了消费者,呃,生产者就不能再生产了,但是消费者的话呢,只要我们消费了一个产品,你就可以在这呢去把对方哎唤醒,就让他可以继续生产了。哎,对是吧。嗯,这这样咱们跑一下。哎,你看这个成语呢,这就这样就一直下去了。那停不了了,这不就是生产点消费点,生产点消费点就停不了了,哎就这样的去执行,因为这呢,咱们设计的他们两者这个sleep的时间呢,有点接近。啊,就是他们生产和消费的这个间隔呢,有点接近了,所以你会看到这个始终对就在这个过程当中了,啊这个我就停了,嗯,你要想这个有点意思呢,你可以怎么办,这是生产生产的,生产的要是快一点,那你可以这个数也不大了啊,你可以把这个改的改成20吧,生产的快一些,消费的慢一些。
22:26
对吧。生产的快吗?生产快,所以你一下子就会看到它就蹦到这个20这块了,是吧,这不很啊很快的,他就会因为你消费的慢嘛。生产的快是吧,那还有一个办法就是你你虽然说这个消费的慢,那消费者就一个人,我再造一个消费者呗。嗯,这个来一个C2C2C2生产呢,咱们是十毫秒生产一个,消费呢,是20毫秒消费一个,那我俩消费者嗯,啊这是吧。
23:11
对,这个得改一下啊,没问题了,走。你看这时候又又又差不多了,那就差不多了,虽然你这个生产的快,呃十毫秒一个,但是我这消费者20毫秒消费一个能俩人嘛,哎就差不太多了啊,就成这样了,行这呢就是咱们这个生产者消费者的这道题目,诶大家呢下来呢可以把它呢写一写,哎涉及到我们这一章目前讲到的这样的一些知识,咱们这一章的重点是哪呢?哎,如何创建多线程啊,以及呢这个同步啊,这是重点啊,那么如何创建多线程这块呢,其实还有这个哎这个哎5.0以后的两个新的特性,这是咱们这一章最后呢,涉及到这个内容啊。
我来说两句