00:00
那么接下来我们得模拟两个线程,模拟两个线程干什么?我们得模拟线程去对这个账户进行取款吧,是不是?哎,那模拟线程各位怎么模拟啊?我们在这呢写个class啊,这个class我们叫with straw。或者叫account线程吧,Thread行吧,就叫account thread。账户线程行不行,然后他去继承谁呢?就直接继承了各位啊,不写接口那种方式的啊。来,那么接下来我们在这儿呢,重写一个方法,Run方法,那这个run方法开始执行,表示取款啊,Run方法的执行啊,表示什么呀,取款操作取款操作各位啊。那么你要注意一个问题,什么问题呢?首先,你必须保证两个线程它能够共享同一个账户。
01:01
那共享同一个账户,那怎么能共享呢?所以你这一块怎么着啊。得有一个实例变量,各位大家看清楚了啊,实例变量。这是一个设计,各位大家注意听啊,哎,两个线程怎么着啊,必须共享同一个账户对象。那么这块你就得有个属性啊,这个账户是不是得传进来呀,你通过什么传,通过构造方法是不是可以传过来,叫通过构造方法传递过来账户对象,那么这个时候呢,我们提供一个构造方法传过来一个account,然后这个参数account付给这个account是不是就行了。大家看,这样的话,我们是不是可以保证两个对象共享同一个账户对象?老师我还是不太理解,大家注意听啊,我在这写个测试程序test,那么这个测试程序呢?PSVM好,最大化之后呢,接下来我们在这写代码,大家看啊。首先第一个我们要创建账户对象吗?是不是,哎账户对象只创建几个呀。
02:03
只创建什么一个,那么这个账对象account account等于new一个account new这个account的时候,就账户的一个账号是杠001这个账户,然后他的余额就是1万。假如是这样的,接下来我们创建两个线程,各位注意听啊,T线程,New,一个new一个什么呀,叫做I account thread,然后把act传进去。那thread tr线程new一个什么呀?哎,这个account thread,然后把act传进去,好大家看我现在是不是我创建了两个线程,我把账户是不是都作为参数传进去了,这个账户对象是不是只有一个。这样的话,两个线程是不是共享同一个账户?大家想这不构造方法吗?对吧?传过来之后,通过它就付给了它,它不就是它吗?对吧,它现在是空,但是当我们这个构造方法执行的时候,是不是就不是空了。对吧,哎,就不是空了,那么接下来我们可以设置name t1线程,假如说s name是T1 T2线程site name假如是T2,那么这个时候我们启动线程取款,T一点start t2点start是不是就启动了呀?启动取款就行了,只要他一启动一启动,那么这边是不是run方法开始执行啊。
03:29
对吧,啊,这个范围开始执行啊。大家看看这个程序啊,这个账户里边有两个属性,然后提供上构造方法,提供了set get方法,提供了一个取款方法,然后这块呢,有一个线程类,对吧,继成thread里边跟一个参数是account,然后接下来你有两次吗?你有一个账户对象,你有两个线程,两个线程里边传的是同一个账户,两个线程T1和T2共享同一个账户对象,然后T1启动,T2启动来执行我们这个软方法来开始取假设取款,假设取款什么呢?嗯。
04:03
取款5000吧,假设取款5000啊,咱们瞅一眼啊,取款5000。Double money取多少钱呀?5000啊,假如有这么一个值取5000,那开始取啊取款那怎么取啊?这不账户对象吗?对吧,他有个方法吧,叫withdraw吧,是不是取款取这么多钱。对吧,那接下来。接下来啊,你可以输出,嗯。嗯。说出一句话是不是,哎,你就说什么呢,叫做取款什么呀,成功呗。Get account number这个。呃,对账户取款成功取款。成功余额。我直接写个余额吧,行吧。
05:02
账户act-001。取款成功,这个账户呢,他的账号就动态获取得了。动态获取act.get act取款成功。余额点get balance吧,行吧,就就这么,就这么。完事了啊,就这么完事了,那么这个程序大家想一想。两个线程对同一个账户进行取款。什么时候会出问题?思考一下什么时候会出问题。嗯。有没有可能?因为你现在是有一个线程执行这个吗?就是两个多线程并发这个方法吧,是不是多线程并发执行这个方法对吗?我们回到这个方法里边啊,和大家思考一下。T1和T2并发这个方法对吧,大家想一想有没有可能T1先进来,或者是T2先进来,总有一个先一个后,对吧,那无所谓了,是不是,那假如说T1线程执行到这行代码39行啊。
06:17
记住,T1和T2是两个站啊,T1和T2是两个站。但各位new对象是不是在堆里边,堆里只有几个?堆是不是只有一个堆,内存是不是共享的?对吧,哎,对内存共享的各位啊,T1和T2并发两个方法啊,并发这个方法,T1和T2是两个站啊两个站。两个站。操作堆中同一个对象看见了吗?就两个站操作堆里边同一个对象。啊,操作堆当中的同一个对象,各位啊,大家注意听,那么假如说T1呢,他进来执行拿到的余额是多少?T1拿到的余额是1万对吧?那么假如说是T1拿到1万,紧接着T2T1啊。
07:14
减去这个余额是多少?5000是不是还剩5000啊,还剩5000只要第43行代码它不执行。只要他不去更新这个账户的余额是不是还是1万。只要T1线程还没有执行到第43行。这个时候T2线程如果从大框里边进来的话,T2线程调get balance这个结果的值还是多少?1万吧,1万减去5000是不是还是5000?大家思考一下是不是这个道理,就是假如说T1和T2 t1线程执行完前两行代码了。T1线程还没有执行这行代码,T2线程从这进来执行了。大家思考一下,就是说思考啊,思考思考什么呀。
08:00
假设T1直行到这里了。但还没来得及执行。这行代码。T2线城。进来什么withdraw方法了?进来with方法了。此时一定出问题,大家思考一下,想想想是不是?想一下啊,想一下。想一下这个有没有道理啊,思考一下,Get balance是1万。那这个是1万的话,那这个1万减去5000等于5000更新还没有来得及更新的时候,另外一个线程进来了。进来了啊,进来之后呢,他调get balance,因为你set还没有执行啊,所以另外一个线程调get balance的时候,它的额度还是拿的是1万,那1万再减去5000,不就是5000吗。
09:00
最后的结果是什么呀?每人取了5000块钱。对吧,然后余额还剩5000,当然各位大家思考一下啊,有没有可能,有没有可能我们在运行的时候不出问题。有没有可能在运行时?不出问题。有没有可能?也有可能不出问题啊。有没有可能在运行时不出问题啊?有可能吧。有可能一个线程进来执行。对吧,他把这三行代码执行88888很顺利,执行完了,另外一个线程再重新进来执行的时候get balance得到值是不是就是5000啊,5000减去5000等于零,S就是零嘛。是不是,所以这个东西有可能会出问题,也有可能不出问题,关键是看你T线程到底执行完还是执行不完,如果T线程执行完。那恭喜你,如果T1限制执行不完的话,那就不行了。
10:04
对吧,哎,执行不管,那看看情况了,这块的话,我们最好能够输出的这个好一点啊,哪个县城。对这个取款。哪个线程来写上a th current.get name?行吧,Get name啊。我们看一下这个概率事件会不会发生在我们身上啊,走一下。啊,这是输出前后的一个问题啊,输出前后的一个问题。嗯。我们这个输出位置在哪,输出会更好一点,你看这是零,这是5000都乱了吧。是不是乱了呀,取款。取款。
11:00
行,就这么着吧,我们再输出一次啊看看。这个取款5000,最后余额是零,你看这个取款5000是吧,也是余额为零吧,这个是正常的是不是。在走。有没有可能两个都是5000?有没有可能两个都是5000来概率事件看一下啊。两个都是零也没关系啊,两个都是5000就出问题了。好,大家看这是不是就出问题了。T1账户对这个账,T1县城对这个账户进行取款,然后余额是5000 t1呢又对他进行取款成功,余额还是5000。这事就出问题了,对吧?哎,我说一下啊,有一种方式可以让它一定出问题。哪种方式?假如说在这两行代码之后,我们在这睡眠一下,在这里模拟一下网络延迟百分百会出问题,你好好想想sleep。
12:02
然后呢,睡1000睡一秒。大家思考一下,是不是因为你第一个线程过来执行,这发生延迟了,还没有更新,第二个线程是不是进来执行,调他这个方法拿到这个钱是1万。对吧,这个百分百会出问题的,你执行一下,你看最后两个都是5000。就不对了。对吧,百分百出问题,你怎么执行它都出问题。对吧,取了5000,取了5000,最后余额还是5000。对吧,那取款这个对他取款多少成功。对吧,你看走一个。嗯。对他取款5000余额是这么多,对他进行取款5000余额是这么多,诶这就出问题了吧。这个出问题的原因是什么?就是这里发生了网络延迟,一个线程进来执行,另外一个线程也进来执行了,表示两个线程同时并发对同一个账户进行取款出现了问题。
13:06
是不是出现了问题啊?
我来说两句