程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> 【JAVA並發編程實戰】8、鎖順序死鎖,java實戰

【JAVA並發編程實戰】8、鎖順序死鎖,java實戰

編輯:JAVA綜合教程

【JAVA並發編程實戰】8、鎖順序死鎖,java實戰


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();
    }
}

測試結果:

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved