JAVA多线程----用--取钱问题2

         在该示例代码中,TestAccount类是测试类,主要实现创建帐户Account类的对象,以及启动学生线程StudentThread和启动家长线程GenearchThread。在StudentThread线程中,执行的功能是每隔2秒中取一次钱,每次取50元。在GenearchThread线程中,执行的功能是每隔12秒存一次钱,每次存200。这样存款和取款之间不仅时间间隔存在差异,而且数量上也会出现交叉。而该示例中,最核心的代码是Account类的实现。

         在Account类中,实现了同步控制功能,在该类中包含一个关键的属性money,该属性的作用是存储帐户金额。在介绍该类的实现前,首先介绍一下两个同步方法——wait和notify方法的使用,这两个方法都是Object类中的方法,也就是说每个类都包含这两个方法,换句话说,就是Java天生就支持同步处理。这两个方法都只能在synchronized修饰的方法或语句块内部采用被调用。其中wait方法的作用是使调用该方法的线程休眠,也就是使该线程退出CPU的等待队列,处于冬眠状态,不执行动作,也不占用CPU排队的时间,notify方法的作用是唤醒一个任意该对象的线程,该线程当前处于休眠状态,至于唤醒的具体是那个则不保证。在Account类中,被StudentThread调用的getMoney方法的功能是判断当前金额是否是0,如果是则使StudentThread线程处于休眠状态,如果金额不是0,则取出50元,同时唤醒使用该帐户对象的其它一个线程,而被GenearchThread线程调用的saveMoney方法的功能是判断当前是否不为0,如果是则使GenearchThread线程处于休眠状态,如果金额是0,则存入200元,同时唤醒使用该帐户对象的其它一个线程。

         如果还是不清楚,那就结合前面的程序执行结果来解释一下程序执行的过程:在程序开始执行时,学生线程和家长线程都启动起来,所以输出“准备取钱”和“准备存钱”,然后学生线程按照该线程run方法的逻辑执行,先延迟2秒,然后调用帐户对象a中的getMoney方法,但是由于初始情况下帐户对象a中的money数值为0,所以学生线程就休眠了。在学生线程执行的同时,家长线程也按照该线程的run方法的逻辑执行,先延迟12秒,然后调用帐户对象a中的saveMoney方法,由于帐户a对象中的money为零,条件不成立,所以执行存入200元,同时唤醒线程,由于使用对象a的线程现在只有学生线程,所以学生线程被唤醒,开始执行逻辑,取出50元,然后唤醒线程,由于当前没有线程处于休眠状态,所以没有线程被唤醒。同时家长线程继续执行,先延迟12秒,这个时候学生线程执行了4次,耗时4X2秒=8秒,就取光了帐户中的钱,接着由于帐户为0则学生线程又休眠了,一直到家长线程延迟12秒结束以后,判断帐户为0,又存入了200元,程序继续执行下去。

         在解决多线程问题是,互斥和同步都是解决问题的思路,如果需要形象的比较这两种方式的区别的话,就看一下下面的示例。一个比较忙的老总,桌子上有2部电话,在一部处于通话状态时,另一部响了,老总拿其这部电话说我在接电话,你等一下,而没有挂电话,这种处理的方式就是互斥。而如果老总拿其另一部电话说,我在接电话,等会我打给你,然后挂了电话,这种处理的方式就是同步。两者相比,互斥明显占用系统资源(浪费电话费,浪费别人的时间),而同步则是一种更加好的解决问题的思路。

posted @ 2017-02-28 16:47  Tritone  阅读(959)  评论(0编辑  收藏  举报