黑马程序员技术交流社区

标题: 如何避免银行转账程序死锁?请赐教! [打印本页]

作者: 朱晓杰    时间: 2013-5-7 23:02
标题: 如何避免银行转账程序死锁?请赐教!
本帖最后由 朱晓杰 于 2013-5-9 18:47 编辑

       今天在整理死锁的时候,自己写了一个小例子,死锁的现象倒是出现了 ,可是在开发过程中要如何才能避免程序死锁呢?据我所知要定义锁的顺序,并在整个程序中都按照这个顺序来获取锁,请问该如何制定锁的顺序呢?下面是我的死锁的例子。

银行转账死锁示例
  1. /*
  2. * 需求:简单的银行转账,它将资金从一个账户转到另一个账户
  3. * 在开始转账之前,需要获得两个Account的锁,以确保以原子的方式更新账户中的余额,且不能破坏不可变的条件,如账户的余额不能为负数
  4. *
  5. */

  6. /*账户类*/
  7. class Account{
  8.         private String accountName;//账号
  9.         private int balance;//资金总额
  10.         public Account(String accountName,int balance){
  11.                 this.accountName = accountName;
  12.                 this.balance = balance;
  13.         }
  14.         /**/
  15.         public String getAccountName() {//获取账号
  16.                 return accountName;
  17.         }
  18.         public int getBalance() {//获取账号余额
  19.                 return balance;
  20.         }
  21.         
  22.         public void debit(int amount){//更新转出方余额
  23.                 this.balance -= amount;
  24.         }
  25.         
  26.         public void credbit(int amount){//更新转入方余额
  27.                 this.balance += amount;
  28.         }
  29. }


  30. class TransferAccount implements Runnable{
  31.         public Account fromAccount;//转出账户
  32.         public Account toAccount;//转入账户
  33.         public int amount;//转出金额
  34.         public TransferAccount(Account fromAccount,Account toAccount,int amount){
  35.                 this.fromAccount = fromAccount;
  36.                 this.toAccount = toAccount;
  37.                 this.amount = amount;
  38.         }
  39.         public void run(){
  40.                 while(true){
  41.                         synchronized(fromAccount){
  42.                                 synchronized(toAccount){
  43.                                         if(fromAccount.getBalance() <= 0){//转账进行的条件:判断转出账户的余额是否大于0
  44.                                                 System.out.println(fromAccount.getAccountName() + "账户余额不足,无法进行转账");
  45.                                                 return;
  46.                                         }else{
  47.                                                 fromAccount.debit(amount);//更新转出账户的余额:-
  48.                                                 toAccount.credbit(amount);//更新转入账户的余额:+
  49.                                         }
  50.                                 }
  51.                         }
  52.                         System.out.println(fromAccount.getAccountName() + "......" + fromAccount.getBalance());//打印转出账户的余额
  53.                         System.out.println(toAccount.getAccountName() + "---" + toAccount.getBalance());//打印转入账户的余额
  54.                 }
  55.         }
  56. }

  57. public class BankTransfer {
  58.         public static void main(String[] args) {
  59.                 Account fromAccount = new Account("张三",100000);
  60.                 Account toAccount = new Account("李四",200000);
  61.                
  62.                 Thread a = new Thread(new TransferAccount(fromAccount,toAccount,1));
  63.                 Thread b = new Thread(new TransferAccount(toAccount,fromAccount,2));
  64.                
  65.                 a.start();
  66.                 b.start();
  67.         }
  68. }
复制代码
分析发生死锁的原因 :所有的线程并不是按照相同的顺序来获取锁,锁的顺序取决于传递的参数顺序,而这些参数顺序又取决于外部输入,如果线程a和线程b同时转账,线程a从张三向李四转账,线程b从李四向张三转账,那么就会发生 死锁:
         a:new TransferAccount(fromAccount,toAccount,1)      
         b:new TransferAccount(toAccount,fromAccount,2)
         如果执行顺序不恰当,那么a可能获得fromAccount的锁并且等待toAccount的锁,然而此时b拥有toAccount的锁,并正在等待fromAccount的锁。
作者: 曹睿翔    时间: 2013-5-7 23:05
哈哈,帮你顶,整理还是有好处的吧
作者: 朱晓杰    时间: 2013-5-7 23:06
曹睿翔 发表于 2013-5-7 23:05
哈哈,帮你顶,整理还是有好处的吧

恩恩,是的呢,这个是死锁中的第二个例子?质量还行?
作者: 曹睿翔    时间: 2013-5-7 23:08
朱晓杰 发表于 2013-5-7 23:06
恩恩,是的呢,这个是死锁中的第二个例子?质量还行?

用代码快<>把代码弄进去,很不错
作者: 朱晓杰    时间: 2013-5-7 23:10
好的,我试着改一下,主推活动发帖直接发就可以了吧?
作者: 曹睿翔    时间: 2013-5-8 23:59
问题解决请编辑改为已解决,有疑问可以继续追问




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2