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