你的位置:首页 > Java教程

[Java教程]【JAVA并发编程实战】8、锁顺序死锁


package cn.study.concurrency.ch10;public class Account {  private String staffAccount;  //账号  private String passWord;  //密码  private int balance; //账户余额    public Account(int money) {    this.balance = money;  }    public String getStaffAccount() {    return staffAccount;  }  public void setStaffAccount(String staffAccount) {    this.staffAccount = staffAccount;  }  public String getPassWord() {    return passWord;  }  public void setPassWord(String passWord) {    this.passWord = passWord;  }    public void debit(int amount)  {    System.out.println("转出账户:" + amount);  }    public void credit(int amount)  {    System.out.println("转入账户:" + amount);  }  public int getBalance() {    return balance;  }  public void setBalance(int balance) {    this.balance = balance;  }  }

 

package cn.study.concurrency.ch10;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import javax.naming.InsufficientResourcesException;/** * 通过制定确定的锁顺序来避免死锁 * @author xiaof * */public class DeathLock {  public void transferMoney(Account fromAccount, Account toAccount, int amount) throws InsufficientResourcesException  {    synchronized(fromAccount)    {      synchronized(toAccount)      {        //按参数的顺序上锁,这个依据参数的调用方法的顺序        if(fromAccount.getBalance() < amount)        {          //账户余额不足,无法转账          throw new InsufficientResourcesException();        }        else        {          fromAccount.debit(amount);          toAccount.credit(amount);        }      }    }  }  /**   * 这个用来在无法判定枷锁顺序的时候的加时赛锁   */  private static final Object tieLock = new Object();    public static void transferMoney2(final Account fromAccount, final Account toAccount, final int amount) throws InsufficientResourcesException  {    /**     * 辅助内部类     * @author xiaof     *     */    class Helper    {      public void transfer() throws InsufficientResourcesException      {        //内部类可以随意访问外部类成员        //按参数的顺序上锁,这个依据参数的调用方法的顺序        if(fromAccount.getBalance() < amount)        {          //账户余额不足,无法转账          throw new InsufficientResourcesException();        }        else        {          fromAccount.debit(amount);          toAccount.credit(amount);        }      }    }    //返回给定对象的哈希码,该代码与默认的方法 hashCode() 返回的代码一样,无论给定对象的类是否重写 hashCode()    int fromHash = System.identityHashCode(fromAccount);    int toHash = System.identityHashCode(toAccount);    //根据hash值判定加锁顺序,那么一样的对象的锁顺序就一定一样    if(fromHash < toHash)    {      synchronized(fromAccount)      {        synchronized(toAccount)        {          new Helper().transfer();        }      }    }    else if(toHash < fromHash)    {      synchronized(toAccount)      {        synchronized(fromAccount)        {          new Helper().transfer();        }      }    }    else    {      //如果很不巧,hash值是一样的,那么就需要一个加时赛的机制,先获取外部锁,然后再此基础上对两个对象随机上锁      synchronized(tieLock)      {        synchronized(fromAccount)        {          synchronized(toAccount)          {            new Helper().transfer();          }        }      }    }      }    static Account account1 = new Account(999);  static Account account2 = new Account(999);    public static void main(String[] args) throws InsufficientResourcesException {    //对于第一个方法很容易死锁    //比如:当有两个同时执行这个方法的调用时候//    DeathLock dl = new DeathLock();    //这个时候第一个调用在锁了account1,然后第二个调用锁了account2    //同时第一个需要account2,第二个需要account1,这就发生竞争死锁了//    dl.transferMoney(account1, account2, 998);//    dl.transferMoney(account2, account1, 998);//    //    dl.transferMoney2(account1, account2, 998);    ExecutorService pool = Executors.newFixedThreadPool(10);    for(int i = 0; i < 5; ++ i)    {      pool.execute(new Runnable() {        @Override        public void run() {          try {            DeathLock.transferMoney2(account1, account2, 998);          } catch (InsufficientResourcesException e) {            e.printStackTrace();          }        }      });    }        for(int i = 0; i < 5; ++ i)    {      pool.execute(new Runnable() {        @Override        public void run() {          try {            DeathLock.transferMoney2(account2, account1, 998);          } catch (InsufficientResourcesException e) {            e.printStackTrace();          }        }      });    }        pool.shutdown();  }}

测试结果: