00:00
嗯,那接下来呢,咱们来去讲解一下,讲解一下的话呢,咱们就,嗯,咱们就这样了啊,咱们在eclipse当中时候呢,是每天呢是写了一个工程,那咱们这块呢,是不是就每天写一个modu了,对,这是咱们第一天的第一天呢,当时讲的时候呢,你看我把这个代码呢,都给写到这个工程的src下了,那我也写到这儿了,哎,那相当于大家也能够明白,就是我们在这个工程的S2C下呢,也是可以写代码的。啊,也是可以写代码的,那只不过呢,咱们这个我放到这就不太合适了啊,我把这个呢,CTRL,嗯,CTRLC一下,我把它粘到咱们这个CTRLV啊D01就是之前咱们前一天的这个,呃,这个代码里边啊,那这呢就是多个type,这不就是多行显示,咱们做过这个设置啊,我就放到这儿了啊嗯,然后呢,这里边呢,我就我就不要了啊。那这个我就清空了,哎,这个也不要了。行,这个就空着它了,这个真正在开发的时候呢,大家比如写个电商,这呢就是你多个模块啊,那就大家呢,在这个模块里边,你去写这个module里边的这个代码就行,然后呢,我们这个工程下的src写不写,嗯,也可以写,比如你多个模块呢,会有一些整合的一些代码呢,你可以考虑写在我们这个工程下,咱们这呢,就是每天讲的一些新知识,我就不往这放了,嗯,那我现在同步呢,再去造一个新的modu,这呢我就叫做DAY02啊好,这呢又是个module,在这个SCSRC下,我们去新建一个package。
01:36
成,然后在这里边呢,我们去演示一下这个卖票这个事儿,咱们呢,先拿这个叫实现的方式,实现方式卖票,说一下实验方式呢,咱们之前是写到这个里了啊,我CTRLC一下CTRLV这个我们就关掉了,好把这个呢我们打开。你先稍微呢来回顾一下啊,咱们呢,让这个WINDOW1呢去实现re接口,有100张票,这块呢,就开始去这个呃买票了,然后下边呢,我们是造了一个window的对象,开启了三个窗口,然后呢去开始卖票,哎,我们执行一下。
02:13
发现呢,其中会有一些问题,比如说这里边这个100出现了三张,显然呢不对,这个呢,我们把它归结为呢,就出现重票了,这就是安全问题的一种啊,那这是一种情况,还可能会出现什么情况呢?比如我在这个TK的这块,一旦你判断是否大于零以后,这个位置,我呢让咱们当前的这个线程,嗯,他呢去这个我就用不着直接去点current了啊,因为咱们这个sleep本身是静态的,哎,我这呢让他去休眠,比如说这个100相当于0.1。秒啊,那sleep呢,本身会抛异常,这时候呢,在咱们ecl当中,你CTRL1一下是吧,在咱们这你就别CTRL1了,Al enter,哎,我们去做个catch。
03:00
哎,行好,那我这加了一个sleep啊,我们现在呢,再去执行。此时的话呢,我们会看到诶,出现了一个负一。复印呢,这叫错票,这呢也是不正常的,如果你去这个售票窗口去买票是吧?啊,好容易抢到票了一看,哎,负一号座那吓一票是吧?啊这个就很诡异了啊呃,那么这个首先说呢,你你要是真正窗口出现这个票呢,首先它不是假票啊,这是一张真票,官方出来的票,但那个票号呢,不对是吧?像这种情况的话呢,一般你就收藏一下,可能还有收藏价值呢,是吧,这个是不对的啊,那么我们现在呢,要解决的就是这样一些问题,你像咱们这个春运,这个被全世界关注啊,这叫什么人类大迁徙是吧?啊,每年中国一次啊,这个得有多少亿人次啊,应该是上10亿了啊啊,就是世界范围内,包括以前也不会出现这么大面积的这个人类,这个应该就是人类迁徙了,相当于是是吧,啊,基本上南边北边人呢,得呼钓一下啊,这个每年一次啊你。
04:14
这每天呢运输这么多人,然后呢,你去卖票的时候呢,这咱们只是卖了100张票,就出来了一个小问题,那你要是这么多张票的话呢,那你可见这个里边有这么多错票跟重票,那不每年就得一场战争嘛,对吧?啊,各个这个这个这个始发站或者这个中间中转的时候呢,都会打打好好多仗是吧?啊因为出现很多重票跟错票的问题了,那现实情况呢,就是没有重票错票,发现还会有些人,呃打座是吧,之前还讨论过这个问题啊,那你这个呢,就更别说你这两张票都是真的了,那样不得打死啊是吧?啊这个情况肯定不行啊,咱们要解决一下,那解决之前呢,先说这样一个小问题,大家你会看到我刚才呢,没有加这个sleep,我没有加,然后我们去运行的时候呢,你看能不能出来这个负一啊,没有我要再跑一遍。
05:07
也没有,我再跑一遍可能还没有,但是我加上这个以后。加上以后基本上呢,我们每次运行可能都能出现。啊,这个有点打脸了是吧?啊,没有啊,这个在家有点慢了,我这都嫌他有点慢。又打脸了是吧,又没有啊,又没有,那就再跑一次呗,是吧,哎,刚才那还挺给面子,还出来了啊。这个好像我看也不理想了,哎,这这也算,这是不是也算这个错票了,对,就是你会发现呢,我刚才呢,刚才我这样说可能这个力度就有点差了啊,就刚才跑了好几次都没出来啊,诶你会发现呢,就是我们没加的时候呢,大家你下来你自己去多跑几次,或者你这个事能想清楚也行啊,就是我们没有加这个sleep的时候呢,这个出现零票呀,或者负一号票的这个概率其实小一些,我说的是概率小一些,你想想说能不能出现。
06:18
对,是能出现的,是能出现的,只不过呢,我加上这个磁sleep以后,相当于呢,强制的咱们就让这个线程进来的时候,到这儿是不是一定会阻塞一下,对,原来呢,我没有加这个sleep啊,没加sleep啊,CPU到这个时候是不是也可能把这个线程一就切换给线程二了,对,也会切换的,只不过呢,这时候可能切换的这种概率特别特别的小,咱们加上这个sleep以后呢,让这种这个切换的概率呢,极大的增大了,增大了啊,你到这儿呢,这个线程立马就sleep了,然后呢,我这个线程二呢,这时候就进来了啊,相当于呢,咱们加sleep的这个这个这个目的,注意啊,我们加sleep的目的不是说原来呢不出现零和负一,加完sleep以后呢,出现零和负一了,这是不对的,对原来也是会出现的,只是说呢,咱们加了sleep以后呢,把原来出现零跟负一的这种概率呢,给它大大的提升了啊提升呢,就是出现了,就是你可能。
07:19
极大的概率会让他出现这些错票了,这个大家要注意一下,原来呢,可能这个概率呢,叫0.1啊,现在呢,你改完以后呢,可能这概率呢有80%啊。那么大家不能因为说你这个出现的概率小,我就不去解决这个对吧。你看我说这样一句话啊,就是说我们去运行这个程序,我运行了100次都没有出错,这个出错呢,你可以理解为就是出现了零和负一票了啊,我运行了100次都没有出错,跟我这个程序本身有没有错是一回事,对不是一回事。啊,你说我们测试,我测试了100次都没事儿,哎跟这个有没有问题其实是两回事儿啊,哎,这个有没有问题呢?相当于你是不是0%和100%的问题了,你要是没有问题,那就是0%的概率会出现错误是吧,就是绝对不会出现的意思,那只要呢,你不是0%,哪怕是0.01%,那都不行,那就是还是有这样的可能性会出现问题的。
08:20
啊嗯,也就是说咱们这个程序你可能跑了这个100次,也没出现这个零跟负一,但是呢,该有安全问题还是需要解决的啊,那这个零点百分之零点零一,比如说你感觉说这个啊,概率好像挺小了,其实这个概率你看怎么说了,你要说去买个彩票,概率是0.01%,那其实是挺小的,那你得买这个买1万次彩票才能中一次是吧,这个概率呢,其实是偏小了,但是你想象一下,比如说春运的时候,假设啊,春运的时候呢,有这个,这个咱们少点说吧,有1亿人吧,中国假设有1亿人现在需要呢,买火车票了,那1亿你去乘一下0.01%,或者咱们这个不说这个事儿了,比如说这个人了,你就说,比如说咱们这个一个月全国发送多少次,这个列车个数呢,咱们也没统计过哈,一个月呢,咱们保守点说这个。
09:21
1万次吧。假设呢,就是一个月全国呢,就发送1万次这个列车,比如从北京到上海,这就算一次啊,一趟列车啊,一个诶就写成这个啊1万次,一个月呢,假如发了1万次,那现在就说说啊,这个列车,这一趟列车出事故的概率呢,是0.01%,你单看这一次列车好像还挺低的,你基本上能从北京到上海或者到那是吧?啊但是呢,如果说一个月呢,全国发送1万次,你1万你乘以0.1%,就是一一呢,就是全国一个月发生一次事故。啊,那你想想这个事儿就很恐怖了啊,那就意味着就是今年一年至少呢,会出12次这个这个火车的这个事故,每个月爆一次,那受不了是吧,你会发现那个高铁从这个包括以前的动车到现在好像也就那么一两对,温州那次是很典型的,也就那么一两次出现过这个事故,温州那次出电了,后来出现一次可能是停电了还是怎么着的是吧?呃,武汉那块的好像印象当中就出现这两次。
10:26
啊,那也就是说呢,对于他们来讲,那个这个出现事故的概率,那控制的0.01%,那都算是很高的概率了,哎,就是这个意思啊,所以我们必须得从这个根上去解决啊,你看着这个数比较小,那你经不住这个基数大呀,啊所以说呢,有这种安全的问题呢,我们还是需要解决的啊,那首先呢,明确一下,大家能够知道啊,这出现了这个安全问题了,那么究其原因呢,其实大家呢,也都能比较清楚,就是因为呢,我们进来以后,第一个线程呢,我现在呢,正在操作这个票呢,我判断一下这个ticket。
11:03
啊,这个时候是大于零的,假设呢,我们最后呢,是不是就剩这个剩剩几张票啊,假设就现在是有一张票吧。啊,这个我看这可能不形象,大家看一下我这个PPT啊,我这儿呢,给大家画了几个图。嗯,动画不是动画。放映。完了好像又大家中午分享的时候呢,每次都能到这卡一下是吧。啊,那那就咱们就直接这样看哈,这呢是一个理想的状态,我这儿呢,咱们有三个窗口,三个窗口呢,然后呢,三个窗口去这个卖票啊,从这个100这个票号一直呢去递减,正常来讲的话呢,这个让方法当中各自呢去判断这个TK满足的话呢,他就接着去做这个输出操作。
12:00
哎,终于出来了。哎,这样的一个操作,那现在呢,有一种比较极端的状态啊,我这个这个这个呃,就是这这还不是极端状态,就是理想状态呢,就是当你到零的时候呢,大家判断衣服都不满足,这时候呢,那就跳出了,哎,咱们else里有个break就结束了,那有一种极端状态。几张状态呢,就是我们现在呢,有这个三个县程过来,我这个时候的票呢,假设就只剩一张了,这有个依附语句,那县程一呢,哎,现在呢,先去执行,我们进入一服呢,判断一下这个TK的是不是大于零,一判断A满足,满足的话呢,我就能够进入这个依附依据。那进入以后呢,哎,这时候呢,它就进入了一个阻塞状态,咱们不是掉了一个Li吗。相当于阻塞了,那么就在线程一阻塞的过程当中,我们这个线程二跟三呢,诶有非常大的概率呢,它也会进来,那因为你这时候呢,票数还是一,所以呢,这个县城二乃至于说我们在县城三场就都进来了,当然他们各自呢也都阻塞过啊这个二呢,进来以后也没有说去,呃捡这个票,输入这票呢,它也给阻塞了,都sleep了,好,那相继的他们就都sleep的时间到了,就进入这个就绪状态,那么CPU呢,后来就相继的会去执行他们三个线程在里边呢,就输出一下,这个时候呢,如果是T1先执行呢,它就输出了一下一,那输出一以后呢,它就减了一个一嘛。
13:24
那么这个线程二呢就输出零票了,呃,线程三呢,就输出负一票了。哎,就成这样的情况了,所以导致呢,就咱们这个程序呢,诶,就会出现这个叫现成的安全问题啊,这的出现的这个叫错票啊,这个重票能理解不。重票其实相当于是不是在这儿啊,对,我进来以后,比如我把这个sleep呢,咱们放到这哈,这样稍的,这样时候呢,这个重票的概率呢,就比较大了,哎,我们某一个线程呢,比如说他把这个100号票呢,输出了,按说呢该减减了,结果呢,到这给阻塞了,那这时候你另外一个进来是不是也是100了,哎,对啊,好,这呢就是咱们描述的这样的问题,不管你是放到这也好,放到这也好,总之呢,都出现了现成的安全问题。
14:13
啊,现在呢就来解决啊,首先第一个咱们描述一下这个问题啊,问题呢,就是卖票过程中啊,出现了这个叫重票。哎,和错票。嗯,好,这是呢,咱们实际通过这个情况看到的啊,重票和错票是不正常的情况,哎,那么把这种重票跟错票呢,咱们就称作叫现成的安安全问题啊,就这种呢是不安全的,那么首先看到这个问题以后,我们就要分析了,这个问题出现的原因是什么。你要想解决它,你得先知道它为什么出现,哎,然后呢,你才能够去解决啊,那么这个出现的原因怎么说呀,嗯,正常来讲,咱们觉得呢,是不该出现的,就是说你这有个线程过来判断这个是不是大于零,好大于零,大于零你就输出一下票号,然后输出完以后呢,你减减,这就你出去了,出去以后呢,呃,接下来可能另外一个线程,当然也可能还是你这个本身线程又进来啊,又判断又出去,又判断又出去,按说应该没事。
15:33
但刚才为什么出现了这个重票和错票呢?对,就是多个线程呢,你会发现呢,我们一个线程进来以后,我执行是不是它还没有出去这个这个整个这个代码呢,是吧,我进来以后呢,没有说完整出去以后别人才进来,是我执行到这儿的时候呢,是不是执行的过程当中别的先生进来导致的呀。
16:01
对吧,对,诶就是出现这样的情况,所以这个问题的描述呢,就是说哎,当某个线程来这个操作这个车票的过程中。啊,尚未操作完成时,哎,这个其他线程哎参与进来。哎,参与进来,然后呢,也来参与进来啊,也来操作这个这个车票,哎,这种情况导致的。能理解吧,哎,这时候这个车票呢,不就相当于咱们所谓的叫共享数据了吗?哎就像咱们刚才那会儿讲的时候呢,说到的这个事一样,哎说你去取钱,你媳妇去取钱,正常来讲不该出问题,就是你取完以后呢,你媳妇家去取,这时候呢,你取完以后就剩1000了,你媳妇家去取2000取不了,哎这时候呢,就支付失败了。啊,之所以出现这样问题,是因为你取的过程当中,你还没有取完呢,你媳妇就去取了才出事的,哎,然后咱们把这个,呃,这个账户或者说这个钱就称作叫共享数据,在咱们这个问题当中,谁是共享数据啊,对TK的这个票票数,它就是一个共享数据。
17:19
啊,那再举生活中一个例子,这个大家下课的时候呢,都去厕所,咱们厕所这个这个坑位呢,是有限的是吧?啊这一个坑位呢,相当于就是一个共享数据,大家谁都可以去是吧?啊那每个人呢,都是一个线程啊,正常来讲就是你进去了,然后呢,你完事了,你出来了,别人再进去,这都是安全的,那么会出现安全问题,就是说你进去你还没出来,那哥们也非常着急,他也一开门进去了,你俩在里边就安安全问题了是吧?啊,就出事了啊,这叫这个县城的安全问题啊。那找到这个问题的原因以后,下一个问题怎么解决呀,如何解决锁对加个锁是吧,就是你进去以后呢,哎,你把这个锁锁上,锁上你可能在里边这个这个这个拉肚子啊,你就一待,待了一个小时,外边呢,即使有一个比你更着急的,那也不行是吧,也进不去啊,只有你这块完事以后,你一出来他才可以进去,这个时候呢,你俩就不会在里边出现这个安全问题是吧?哎,那从这个卖票的角度来看,就说我们这一个线程呢,进来了,我进来以后呢,我在这睡着了。
18:37
我睡着了,你们也得在外边是不是等着呀,等我睡醒了,哎,我把这个票这个这个输出了啊,也减减了啊,你们再进来啊对这呢,就是咱们的一个解决措施啊,那如何解决描述一下,就是当一个线程哎在操作共享哎操作共享数据的啊,或者就直接说操作这个票票吧。
19:05
啊,操作这个T啊的这个时候其他线程啊,这个不能参与进来啊,然后直到呢。看这个咱们说当一个线程A吧,当一个线程A在操作TK的时候呢,其他线程不能参与进来,直到这个线程A,诶操作完,操作完这个哎,TK的时候。诶,其他县程才可以参与进来,其他线程才可以啊,然后呢,这个诶继续的诶或者叫才可以开始啊来操作这个TK,这种情况呢,即使我们线程A出现了这个阻塞也不能被改变啊,这种情况哎,即使这个线程A啊出现了这个阻塞,它也不能被改变。
20:10
也就是说呢,即使比如说你打开这个这个某一个坑位的这个门了啊,你一进去,结果进去以后呢,这个挺舒服的,睡着了,Sleep了是吧?哎,即使你睡着了,外边这些人呢,想进去也进不去啊,这个时候呢才是安全的好这呢是咱们从这个生活的角度呢,来说一下问题出现的原因和如何解决,那下一步呢,就得看咱们在Java当中是如何来解决的啊,这个咱们先停一下。
我来说两句