00:00
那刚才呢,我们把这个同步代码块来处理,叫实现的这种方式的现场安全问题呢,我们就解决完了,诶大家呢,尤其需要注意两个问题,第一个呢,就是说先明确一下什么是共享数据啊,先明确下谁是共享数据啊,只有有共享数据的这个多个线程,我们才我们说呀,才会出现现程的安全问题,第二多个线程都没有共享数据了,它就不会出现现程的安全问题了,哎就像咱们这个,呃,前一天讲的时候呢,咱们做的这个练习,这个练习当中呢,说一个线程呢,变成变了100以内的偶数,一个呢变了100以内的奇数,大家呢,没有什么共享数据,你干你的,我干我的,那这时候呢,是不会有线上安全问题的啊,那么有线上安全问题呢,一定是他们有共享数据了啊,那大家首先要明确的第一个事,就是说你有没有共享数据,言言之意就是说会不会有现场安全问题了啊,然后接下来呢,你需要知道呢,就是操作共享数据的代码是哪些。
01:00
因为这些代码呢,咱们需要用这个S呢给它包起来啊,这是我们说的这个主要的第一个事情啊,有没有共享数据,然后呢,这个共享数据是谁?然后呢,操作共享数据的代码又是哪些,这是整个呢是第一个问题,第二个问题呢,就是我们在包起来的时候呢,还需要处理一个叫同步监视器啊,那同步监视器的话呢,有一个比较宽泛的,就是说哪个类上都行,在这方面呢没有要求啊,那同样的对应的有一个严格要求比较高的,就是说多个线程呢,必须共用同一把锁啊,只有这个满足了它才可能是安全的啊,否则的话呢,这个仍然不对啊,啊这呢是咱们刚才已经讲过的,那在这个PPT当中呢,我这还画了另外一个图,这个呢,也可以让大家呢,稍微形象点去理解。哎,大家看一下,呃,这呢是咱们在这个TT呢外边是有这个if服啊等等都是相当于操作这个T了,我们用一个S的这样一个,呃,同步代码块呢,把操作T的这个代码呢都包起来了,这个S肯定是在咱们这个RA里边的啊呃,接下来呢,有三个线程去操作这个票,操作票的话呢,大家就需要去这个,我们可以想象点理解,去抢这个西奈关键词后边这个叫锁。
02:18
对,你可以形象点去理解叫抢啊,就谁抢到了,谁就去执行我们这个同步代码块了啊,那么这时候抢也行,或者说呢,大家你看我这呢,有一种状态就是这个叫绿色的啊,就相当于是你这个看到那个车厢的那个厕所那个灯是个绿的啊,那么谁抢到这个了啊,谁抢到这个锁了,那么谁就进去了,谁进去以后,那紧接着就把这个门给关住了。哎,这个我整的观南没炎是吧,没完全覆盖是吧?哎,你就当当成这个完全覆盖了啊,就是你进去以后呢,这个灯就变成红的了,那此时的话呢,这个T2跟T3,乃至于还有其他的线程,一看到这个是红色的了,它就进不去了,因为呢,你没有获取这个同步监视器,哎,那么人家这个线程一呢在里边啊,这是咱们用任何一个类的对象都能充当,但是呢,只能有这一对啊哎,红色绿色这样的一个这个这个对象啊,然后呢,这个线程一呢在里边呢,就一顿操作,即使呢,你在里边呢,被挂起了啊,这个阻塞了等等,哎,都不会改变这种状态,嗯,然后呢,诶,我们这个线程一呢就出来了,它出来以后相当于操作完这个同步代码块中的代码了,它出来了,你就相当于是释放这个同步监声器了,这时候呢,这个状态呢,又变成这个绿的了,那么这个时候呢,他们其实这时候T是还有机会再抢的,就是你一出来这种药又拉肚子了是吧。
03:41
就是大家才去抢啊,你有可能还还还被你抢到了是吧,这个这时候他们就不是严格的一个,这个像消息队列一样是排队了啊啊这个时候呢,就是大家可以理解为是一个强的状态啊,就是CPU呢,因为在切换嘛,啊在切换他们那有可能切换成T1T2或者T3中的任何一个啊好,那就又变成这种状态了,行,这个大家呢,稍微的形象点去理解一下这个过程就OK了,那么接下来呢,我们去考虑一下咱们卖票的程序当中,那你不光是这个实现的方式有这个安全问题,咱们这个继承的方式呢,也有安全问题,咱们现在呢,用同步代码块的方式来解决一下,咱们这个继承的方式中的现场见问题啊把它呢,把它CTRLC也行,或者我这样啊,咱们在这我再去新建一个。
04:32
新建呢,我这个叫咱们就接着往后排了啊,我这叫window test2了。嗯,在这啊,然后把咱们这个,诶继承的方式里边的这个代码给大家拿过来,从这一直到这儿,诶CTRLC粘到咱们这个这里边。上过来呢,我把这个改成是二,咱们上面这个window呢,这个我都改成二了,就是这个都往下这个顺了。
05:11
行,那咱们这块呢,就完全的是咱们这个新的这个代码了,嗯,那么在这个题目当中,同样呢,会有线上的安全问题,咱们也可以去体会一下,比如我让这个出现的概率呢增大,咱们在这个位置呢,给它加上一个sleep,嗯,这呢我写成100了,然后out enter一下,我们去拆开处理一下,好,此时呢我们执行。行行这就结束了,这呢属于这个错票上面看看有没有这个重票啊啊也有好这呢就属于这个现场的安全问题了,那么这呢,相当于咱们使用使用同步代码块来解决。哎,这个叫继承thread类,哎方式的现场安全问题。
06:04
嗯,这个呢,我们把这个放到上面吧,保存一下好使用这个同步代码块,呃,首先呢,咱们先明确一下,这里边呢,显然是有共享数据的了啊TK的,然后接下来明确谁来操作共享数据,还是跟咱们上个问题一样,还是这些啊,还是这些,然后这些的话呢,我们就需要呢,给他拿这个CNE呢去包一下了,哎,西袋子包一下这个位置呢,我们来一个这个诶括号啊,然后把它呢扔进去。好,这就放进去了,放进去以后接下来呢,我们需要考虑的就是这个同步监视器了,同步监视器我们说拿个对象去充当,如果呢,你对刚才那个代码呢还有印象,咱们当时呢,是在这个位置呢,去扭了一个object对吧?哎,那我们就private,呃这个private加不加到都还好啊,诶主要呢,后边我们去把这个对象呢去扭出来。嗯,好了,那么写完以后,我们这个obj ctrl c我就扔到这儿了。
07:02
啊,如果你要是返校前一个实现的方式的写法,这样呢,就算是完事了啊完事以后这是我们试图呢去执行一下,看看此时呢是否安全了。明显的已经发现问题了,不安全。嗯嗯,这时候呢,还是会出现这个重票了,那么相当于这个呢,解决的没成功,那么回过来看一下,为什么为什么呀,你这个时候的这个OB接是锁,咱们要求怎么着得唯一吧,那这时候唯一吗?不唯一不唯一,这有几个。这个里边是不是有三个呀,嗯,咱们下边呢,用用了三个WINDOW2的对象,每一个对象是不是有一个实例变量,这都是咱们变量对象的这个知识了,那么每个线程有一个接,那显然这就不是共享的了,这不就出错了吗?
08:03
那要想解决这个问题怎么办?是不是必须要把这个保证唯一的话,你得整一个static,这样的时候呢,我们三个window的对象才可以共享这一个五节了,哎,我们跑一下。那这个时候呢,它其实才是对的啊,这怎么都窗口一了呢。真的是窗口仪是吧?咱们这个代码有问题吗?看看其实没啥问题,再跑一遍。这不就好了是吧,哎,这个恰好这个CPU呢,太青睐于他了啊。行,这就没问题,这呢我们就解决了这种的,呃,继承方式里边的现场安全问题了,所以大家呢,一定要小心一下,咱们刚才提到的这个情况,说他呢必须要共用同一把锁啊,在这个继承的方式里边,咱们前面讲两种方式的时候呢,也提到了,说这种实现的方式呢,它天然的,你这个实现类当中,它就是属于叫共享的数据了,这个里边天然的这些数据呢,都是共享的。
09:19
啊,你像你这个是共享的,我这定一个这个dog,这也是共享的,因为呢,咱们就造过一个window的对象啊,这就天然是共享的了,而我们这个继承的方式呢,不这样,因为这块造过多个这个对象里边呢,这个只能是一个类变量才行。哎,这要注意一下啊,好,这是我们说的这个,然后咱们再稍微多说两句啊,那像这呢,咱们还得每次都得写上这个对象,包括咱们这个实线里边啊,我还得去一个dog,或者去扭一个其他的对象,说有没有这个稍微简的,这个最便的一个对象,我可以用的,如果要的话呢,省着咱们啊,我还去new个dog,我去new一个object,还稍微有点繁琐。
10:01
那这时候就想有没有相对比较简单的一个对象可用,只要保证唯一就行,对,哎,叫当前对象,那当前对象呢,咱们在前面讲关键字的时候,用谁来表示啊,哎,用这词来表示,那大家看这个位置呢,我就不用这个dog了,好,我在前面去写一个啊呃,S的这个位置我就写一个this。行不行,首先这次是个对象,叫当前对象了,这个位置呢,其实还是个对象啊,哎,是没问题的,那么这次只要保证唯一就行,那问这个时候的Z是谁。是不是就是它呀,呃,因为咱们这个,呃后边呢,能看到说咱们造的是W,这呢相当于是动态获取的啊,动态获取的你这个Z,咱们说就是调这个方法的对象就是Z,这个方法呢,是在你这个WINDOW1中定义的,那就是WINDOW1的对象是不是就是Z啊,咱们自始至终是不是就只造我一个window对象,所以这个这次这个W呢,就是唯一的呀。
11:15
哎,所以这时候这个Z啊,它呢,这个咱们在这在我在这样写一下这个注释啊,此时的这个Z在咱们这个实际问题当中啊,啊就是表示啊,或者就是它为代表的就是唯一的啊,这个WINDOW1的对象。对小啊,后边这个注式呢,咱们可以理解成是另外一种方式了啊,方式二吧,哎,所以呢,最方便的这个方式呢,就是我们这呢,就写一个这次就行,用不着大家再去这个new一个dog啊,New一个object,直接写一下this就可以啊,用当前对象去充当。好,这个要清楚以后那回过来这个位置的话呢,能不能也写成这。
12:07
哎,这个时候呢,大家就有这个呃,这个这个判断的这个能力了啊,这个这次的话呢,叫当前对象,那就是WINDOW2的对象,那我们这个时候WINDOW2几个呀,三个啊不唯一的,所以这时候呢,我们呃,你用这种方式是对的啊,这个咱们看成是一种方式,然后用这个我这样写吧,这个CTRLX这个放到这儿啊,这是一个正确的。哎,而我们这种方式它是错误的,先把它打开吧,把你下边这个呢注释掉。哎,这是一个错误的啊,这个方式啊,为什么呢?因为此时的这个Z代表着啊,这个咱们叫T1T2T3啊,这有三个对象。
13:03
嗯,对象呢,只要不为一,相当于这个锁就不为一,锁不为一,那就会形成有安全问题了啊行,这个还不能往前移了。那就这个往后移一下吧,让他对应一下,好,这个就不可以了,那这个不可以呢,那现在好像说,诶,那我只能是造个对象了。呃,实际上呢,也有一种,也有一个比较方便的一个写法,只不过呢,不是这样写了,我可以写谁呢,这呢相当于是一个新的知识,大家没有见过的,把这个呢,我们再注释一下。嗯,这个呢,我用谁呢,这个位置我可以写叫window2.class。对,这个呢,没见过啊,这属于一个咱们的新的知识,就是我们拿当前这个类去充当,诶类还可以充当,咱们刚才那会讲了,说这个叫同步监视器,说的是不是对象才可以充当呀,那类写到这也不错,哎从语法上你看不错,从运行的角度呢,其实也不错,跑一下。
14:13
哎,你从这也大概能看出来,他这时候也没有错误。那。你这个反推一下,这样写也没问题,而这个位置呢,又要求是一个对象,你写了个类,你能反推出来什么结论呢?是不是类也是对象啊,对吧?哎,类也是对象啊,这些同学就懵了。类也是对象,所以你从这个角度上来讲呢,我们说叫面向对象,面向对象,这不才真的是面向对象了嘛,原来我们说对象调方法,调属性,后来我们说有静态的,说静态呢,是可以通过类去掉的,好像说呢,好,还不可以,还不止可以通过对象去掉了,类还可以掉了,那现在告诉你说类也是对象,这不就真的是通过对象来调的嘛,是吧?诶面向对象编程啊,那我们看到的其实都是一些对象了,类也是对象。
15:05
类也是对象这个事儿呢,咱们到后边讲到反射的时候呢,给大家详细的去说啊,呃,也就是说到那个时候呢,我们会看到这样的一个结构,我呢有一个类型叫做class,注意啊,我这不是关键字。我这个C是大写的,就是有一个类叫class,这个类呢,我们随便给它起个名吧,比如我叫class,这个你就别别写它了。这是不是成关键字了,对,咱们不是标志符,不能用关键字吗?我写成ZZ啊,诶后边呢,我们就拿这个WINDOW2去充它。这就相当于你从这个变量的定义上来看,这是一个类的类,这就是你这个类的一个变量了,右边呢,是不是就你这个变量的一个值,你这是一个类类型的,这不就相当于你的一个对象吗。啊,那就说明我们这个类呢,它其实可以作为一个对象出现的,谁的对象呢,是这个类的一个对象,先不要去深究啊,先不要去深究,你从这个形式上呢,能够理解这个WINDOW2呢,是个对象就行了,好,那我们先知道第一个事儿,它是个对象,第二个事儿,这个对象呢,得是唯一的。
16:13
那么这个时候的window2.class,你这样写的,它是唯一的吗?是唯一的咱们到后边讲反射的时候会说这个类的话呢,我们只会加载一次啊这个WINDOW2。哎,它呢,诶只会诶加载一次,只会加载一次,意味着它就只有一个,所以呢,我们用WINDOW2也是可以的啊,也是可以的啊,这相当于是一个新的知识点啊,咱把这个事呢,稍微描述一下啊,就是在咱们刚才讲的这个实现方式当中,呃,这个任何一个都可以充当这个锁啊,要供一把锁,咱们在这个位置呢去呃说一下啊,这个是一个补充。哎补充什么意思呢?就是在这个,嗯,这个叫什么呀,实现哎reable这个接口的这个方呃,实现认证接口创建多线程程的这个方式中,说我们呢,可以考虑使用Z啊来充当这个同步监视器啊,哎,使用这个Z来充当同步监视器,注意我这时候说的可考虑哈,就我没说一定可以。
17:34
因为你还得具体问题具体分析,看这个this是不是同一个啊,所以这块呢,只是说可以考虑,那么回到咱们这块,这块呢,咱们写一个这个说明。说明呢,叫什么呢,说在这个继承thread类的,这个thread类创建。多线程的这个方式中。
18:02
啊,大家呢,要慎用。Z啊来充当这个叫同步监视器,注意我这时候我也没说一定不能用,还是得具体问题具体分析,你看你这个Z呢,是不是唯一的啊,看是唯一的慎用这个Z充当同步监视器,那么你呢,可以考虑使用当前类啊来充当哎同步监视器。嗯,不管呢,你用谁,总之呢,大家一定要考虑的一个事儿呢,就是一定要保证它是唯一的就可以了。啊,一定要保证咱们刚才讲的这里边儿的这个事儿。哎,它这是唯一的,哎,共用的是同一把锁。啊好,又强调一下,又强调了一下这个问题,那另外呢,就是再多说一句,就是咱们刚才呢,讲到叫共享数据了,这其实也是咱们的一个难点啊,就是大家呢,你得明确谁是共享数据啊,然后呢,把操作共享数据的代码呢给它包起来。
19:02
这个时候呢,也要小心一个问题,什么问题呢,就是不要包多了,也不要包少了啊,这个咱们就通俗点,在这我加一个这样线啊,不能这个这个这个包包包应该都能理解是吧。不是那个包啊,不是package不能。换一个词吧,括号多了,哎,不行,不能这个这个这个还得包含行啊,哎,不能包含多了,包含代码多了。啊,也不能啊,包含代码少了就是啊,把同步的需要被同步代码包起来,不能多了,不能少了,这个不能少了,大家好理解是吧。比如我这操作共享数据代码,一行两行,三行四行,我这有四行是需要呢,哎,你包起来的结果呢,你把这两个包起来了,这两个没包,这时候这不就会出现问题,就是你这个过来以后,过来以后呢,然后执行它到这呢,是不是有可能阻塞。
20:09
这样一组,它那个要过来以后呢,是不是这时候呢,是不是又操作这共享数据又乱了,哎对这种呢好理解啊,就是包少了不对,这个好理解,那么包多了还不对呢?嗯,对,大家有的时候可能会想这个你操作共享数据是这,然后有的时候呢,保险点就跟咱们比如说你写那个踹一样哈,咱们说可能出现异常的代码,这个时候呢,我们多包一点是不是也没事儿啊,诶也没事,多包点也没事,这个时候呢,诶可能反正还更好一点,是吧,多包一点,那么对于我们这个C袋子来讲就不行了啊,你多包了不行,大家刚才提到一个情况就多包了,你这个效率不就低了吗?本来在这块呢,不含共享数据,我们实际上可以看成叫并行一样啊,你这块也包住了,是不是就这时候呢,也成单线程了啊,这是一个问题啊,但这还不是主要的。
21:02
主要的就是有时候你包多了吧,他就错了。啊,怎么叫错了呢?就是这个题意描述的就不对了,你看啊,咱们这里边我包的时候是不是没有包这个Y处啊,那有同学可能会想,这个外处这个包住得了,那你就是不是把这个就成了这样了。这个idea果真很智能啊,往上移一下,他给我整到这了,这个呢,还out下一下。咱们手动的CTRLX一下是吧,哦,带CTRL项啊,这样CTRLV一下,这不就他俩交换了一下。哎,交换了一下,相当于我们把这个外处呢也给包起来了,这不这个括号就在这儿了,我们这个西寨呢就包到这了,那这个时候你看看这个首先安全吗?安全那挺安全的,包多了还真不安全是吧,安全啊,那有什么问题呢?
22:01
对,哎,就成了,是不是一个县城一直把这个票就全都搂完了。你看这时候他还是安全的,就这时候你说诶就窗口二,你觉得可能是巧合,巧合,那你就再跑一遍,再跑一遍你就发现这个还是巧合,但那个巧合的次数有点多的时候呢,它就不是巧合了,就成一种必然了,是吧,你看这时候就都是窗口一了。哎,还是安全的,但是呢,跟这个歧义呢,就不一样了。相当于一个线程进来以后,他拿着这个锁在里边呢,一顿循环呀,都循环完出去了,其他这俩在这等了,等了半天了,你出去了以后,这家一进来说诶没票了是吧,哎,就被玩了成了是吧?哎,你这个外务处呢,显然不能加进去啊,还是要放到外面的,所以包多了包少了都不行啊,这呢也是一个技术活啊,两个难点啊,两个难点,第一个共享数据这块,第二个呢,同步监视器这块啊,这个大家明确一下。
我来说两句