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();
}
}
測試結果:
