00:00
诶看下这道问题,这个题的话呢,其实就是典型的来练习一下创建多线程,以及呢来处理线程的安全问题,这呢提到了一个账户,然后呢有两个储户,两个储户呢共用同一个账户,这呢就叫做共享数据,他们分别呢往这个账户当中去存钱,每个人呢存三次,一次呢存1000。啊,都来操作这个共享数据了,嗯,然后这块呢,是整个出现这样的一些情况啊,咱们呢,就来做一下这道问题。哎,这个呢,咱们去新建一个包来写这个练习。嗯,这块我们去新建一个class,嗯,这是关于这个账户的,嗯,或者叫客户的,这个我就先写成account了,Test。好,来看一下这道问题,这个问题呢,首先咱们来分析一下。嗯,两个储库,那分析的话呢,那就第一个点是否是多线程的问题,显然是对吧?啊,那是多线程,那这里边儿就涉及到这多个线程分别是谁呀。
01:11
对,就是两个储户线程,那回头咱们造两个线程呢,它代表的就是两个储户了,这第一个,然后第二个是多线程,就一定会涉及到线程安全问题吗?不一定吧,诶有没有线程安全问题取决于是否有共享数据,哎,那这呢,我们就写是否有共享数据呢。有谁呢,账户吧,哎,你说账户也行,或者你说这个叫账户的这个余额也行,实际上你账户都是共享了,那余额也是共享的了啊这第二个问题好,那既然有共享数据了,那下个问题呢,自然而然就会出来了,说是否有现制安全问题。对,你要有共享数据,这两个线程呢,还都来操作共享数据,那就一定有。
02:06
啊,那既然有,那我们就需要,哎,考虑如何解决。啊,有,那我就再换一个啊。需要考虑如何解决线程安全问题。哎,这个呢,我们就使用这个同步机制啊。同步机制,这是呢,泛泛的这样一说,呃,具体来讲的话呢,我们说有诶三种方式,哎,刚才呢,咱们还讲了一个lock的方式,行,那这个题目的话呢,就是考虑这几个点就行,下面呢,咱们就这个一块来写一下了。嗯,既然呢是一个多线程的问题,我们就需要呢来创建多线程,咱们讲了目前为止讲了几种方法创建多线程啊。对,目前呢,就说了两种啊,咱们这一章呢,最后呢,诶可以再讲两种,就是在GDK5.0的时候新增的啊,诶目前呢,咱们讲的两种呢,属于一开始这个JDK呢,在提供这个线程创建的时候呢,就给的方式集成外类和实现re切口,那么这个问题咱们用哪个呢?
03:13
都可以。是吧,都可以啊,用哪个都行,大家呢下来呢,可以去写一写实现的方式啊,因为大家可能更习惯上或者更愿意用实现了啊,那这呢,我写成一个继承的啊,写成个继承的,写这个继承的时候呢,你就要特别小心,你得保证呢,大家得去共享这个数据,你不能说你这拗了一个储户啊,你有一个账户啊,我用了一个储户,我也有个账户,那就没办法共享了。哎,那咱们怎么去做呢?我这呢,诶专门的造一个class,我就让它当成是一个账户,诶就专门当成个账户,然后呢,我再造一个class,比如就叫做customer吧,客户啊让他呢去继承于TH类。
04:00
诶集成酸类我怎么就能够体现两个不同的这个客,这个这个账户啊,这个这个这个储户,因为咱们一会就要在这的时候呢,是不是你得去NEW2个customer了,我NEW2个customer呢,我让他们共用同一个account,怎么做到呢?不用静态我这样来做,我清明一个叫private,叫account类型的account,接着呢,我在构造器当中。嗯,Out shift s咱们不是讲过吗?构造器,哎,我呢构造器,构造器的话呢,咱们就就用。他要问我调浮力的哪个,我就调他吧,OK一下。OK一下,这样。我在这个构造器当中,把我们这个属性做一个实例化。哎,那这块我们怎么写呢?回头我可以这样啊,我account act等于new一个account,然后我们去NEW2个customer,哎,这呢,我把这个A呢扔进去。
05:05
ACT。这个out enter。哎,这呢我叫C1,好,然后CL下再来一个C2,此时我两个线程是不是就共用的是同一个账户了,诶这样呢,我们就巧妙的把这个问题就解决掉了,呃,先让他俩呢是共用同一个账户啊嗯,后边的话呢,你这个呃接着做线上这块呢,就给他们各自取一个名呗,比如说这个呢人呢叫甲。哎,另外一个叫乙。嗯,咦咦。行,这是这两个人了,然后这两个人的话呢,起完名以后,接着呢,你不就是让人家去大的方法去启动这个现场去存钱吗?那存钱呢,就会调我们这里边这个重写的run方法了,那下边我们就把这个run呢就重写一下呗,那对于这两个人来讲呢,他要做的事就是存钱,存钱的话呢,说还得呃分三次去存。
06:09
那就得写个for循环。负二到三。你看到三,那我们做的事呢,就是你拿着这个账户去往里边去存钱,那这个账户里边呢,咱们有一个private double类型的一个叫余额,哎,我就叫balance吧。哎,这叫余额了。成,那你也可以去提供这个构造器,Out shift s构造器啊,就调了一个balance啊,把这个实例化一下,一开始呢,咱们在这new的时候呢,假设一开始这个账户就没有钱,你就写个零。啊,你要有钱,你就指定一个数也行啊,那咱们要做的事呢,就是咱们在每一个储户,它通过这个for循环调的时候呢,咱们让这个actct呢,哎,去往里边去加钱,那你加钱的话呢,就得需要在上边这里边去写一个是不是往里存钱的一个方法呀,哎,咱们前面讲面向对象的时候呢,就是账户里边也都是写了一个方法public VO,嗯,存钱咱们当时叫这个deposit是吧。
07:12
存了多少钱,通过这个擎参呢?指明,嗯,Double类型的AMT吧。啊,这样的去往里存啊存钱你判断一下也行,AMT呢,你得让它大于零,你别整那个负数,然后我们的balance。哎,加等于这个AMT这呢就存钱了,存完以后呢,我们这时候呢,写一句话啊啊说这个叫存钱成功啊,那么这个余额为,哎,咱们看一下存完以后当前是多少钱。哎,这么着。能理解吧,嗯,这就写好了,呃,在咱们这个idea当中,就是你写这个方法,如果这个方法呢,这个方法呢,你又没用过它就是这个灰色的。
08:01
嗯,我下边呢,这不就要掉吗?哎,咱们通过这个actd点,咱们去调这个deposit,每次呢存1000,哎,你看这时候呢,它就不是这个灰色的了啊。然后呢,存1000块钱,那个你就一个循环,循环完以后你就存完了。啊,这个呢,就算是结束了,那么这个存的时候呢,咱们让它稍微慢一点啊,这个咱们可以考虑加上一个sleep,加上sleep的话呢,在哪加呢。我加到这儿吧。因为这里边儿我们这个AMT呢,其实也相当于是,呃,不是AMT这个balance也相当于算一个共享数据了。啊,那这个共享数据在操作的时候呢,呃,你得保证它是一个线程安全的啊,现在呢,其实它是有这个风险的,正好咱们把sleep加到这儿呢,呃,你来看一下它这个是不是有这个安全问题,比如说呢,我在这个和这个操作共享数据的代码当中,我给你整一个sleep。来一起啊,短一点吧,来长一点吧。
09:03
1000,然后呢,这个方法咱们一下这个我就开开始了。行吧,嗯,好,那这样的话呢,咱们把这个代码呢,就写完了,此时呢,没有考虑去处理现场安全问题啊,咱们跑一下看看这时候会出现什么情况。哎,这个咱们没写谁存钱,把这个补一下,说这个谁存钱怎么写,谁存钱成功余额为多少。我是不是直接写这个叫thread点啊current th.name就行,我写一个这个啥吧,写个这个冒号吧,这样。因为这个操作呢,这不就是两个线程去做的,两个线程一个叫甲,一个叫乙吗?嗯,哎,执行。哎,这就完事了。
10:01
呃,大家呢,应该能看到这是不是就会有这个现成的安全问题了,嗯,这个乙呢,他一开始存了1000,一开始账户是零,他存了1000以后呢,莫名其妙的就会显示2000。啊,然后呢,下边也类似,这都也算是叫安全问题,就是你不正常了,不对了是吧。这个能理解这个原因吧,嗯,就是呢,呃,这呢,咱们这是乙先存的啊,这个已进去呢,它加了一下存了,只不过存了以后呢,他没有马上去输出啊对,睡着了啊,那在他睡着的这个一秒当中呢,这个甲呢就进来了,甲这时候呢,也把这个钱给存进去了,然后这时候乙醒来了啊甲呢后续也醒来了,然后他俩一输出就哎都是2000了。哎,这就是现场的安全问题,那去处理一下它,处理一下它,我们使用S的使用lock都可以。啊,那如果我要是使用一下这个C的。
11:02
怎么写?我直接把它是不是加上一个西红站就可以了。就他俩呢,去存的时候呢,你一个人存完以后,另外一个人是不是再进去存啊,哎,这就可以了。哎,去转一下。你看这样的话,那就不会出问题了。啊,这里边儿呢,只是凑巧啊,这已就三次就全全整进去了,诶我看看啊。啊,对,凑巧的是吧。因为咱们呢,针对于它呢,里边加的是是一个这个同步的,咱没有说把这个run给加成同步的哈。看看能不能出来那个效果呢。哎,都是这样的是吧。那这样那就这样吧啊,这时候呢,实际上他们是有可能出现交互的啊,这个没问题啊,那这个题目呢,咱们相当于就给解决好这个问题了啊,那么大家呢,也可以去使用咱们这个lock的方式啊,去熟悉一下去使用啊,那需要说一个小问题,就是这个lock。
12:11
咱们刚才已经讲过了啊,这个lock的话呢,我这是用的实线啊。我这是用的实现的方式,实现的方式呢,在这个run里边,咱们用的这个lock,这个lock对象。咱们对应这叫run方法,你可能创建了两个,创建了三个,这几个线程是不是共用的同一个lock对象啊。哎,所以我这块去lo下边unlock这都是对的,如果大家呢,你下来练的时候呢,你写的是继承于类。你要小心一点,你要是继承的方式呢,造了好几个线程,这个时候呢,这个lock呢,怎么办呀。对,是不是得加个静态啊,哎,你得保证呢,相当于这时候这个lock你去锁,这个去解锁,大家得用同一个锁去解锁。你这个线程去lock锁住了,然后另外一个呢,还有一个对象那不行。
13:00
啊,就是也得保证这个lock这个对象呢,对于这几个线程来讲是唯一的啊,这个大家要注意一下。行,这是咱们说的这个这个这个事儿,然后回到咱们这个练习这。回到咱们这个练习,这大家呢,你会发现呢,诶我这是用的继承的方式。这种的方式呢,咱们这里边写了一个同步的方法。上午咱们讲说同步方法解决继承的方式,这个现场安全问题的时候呢,说要慎用。这个这个不是慎用了,就是你要写这个同步方法的时候呢,说那个同步方法尽量的一般都是静态的是吧。啊,你看这里边呢,咱们就没涉及到这个静态,那就说白了,就是我们这个方法呢,用的是Z,咱们不是说在继承方式里边那个同步监视器慎用Z吗。还记得不,我这都都有凭证的啊嗯,在这儿在继承这种方式里边呢,大家呢,就慎用这个Z,因为很多时候这个Z是不是都不唯一啊,大家都不够用的,但是我这儿没有说说不让用啊啊,只是说慎用,你还得具体问题具体分析,你看咱们这个问题中。
14:23
我这不就相当于是用的这次吗。嗯,我为什么能用呢?因为我此时的这次不是你这多个customer,我是不是他们共用的唯一的一个account了。Account是我这个Z,而你这俩人呢,用的用的是同一个account,所以当然就没事了。所以说呢,关于继承也好,时间也好,没有说不让用Z啊,关键呢,就是大家还得具体问题具体分析,这个Z到底是谁,多个线程是不是用的是同一个Z,只要是同一个Z啊,就仍然是能保证线程的安全性。
15:03
啊,这个呢,就是具体问题,大家具体分析就可以了啊行,那咱们。
我来说两句