1. 程式人生 > >通過鎖順序來避免動態的鎖順序死鎖

通過鎖順序來避免動態的鎖順序死鎖

通過鎖順序來避免動態的鎖順序死鎖

歡迎關注作者部落格
簡書傳送門

前言

  兩個執行緒試圖通過不同的順序獲取多個相同的鎖。如果請求的順序不相同,那麼會出現迴圈的鎖依賴現象,產生死鎖。但是如果保證同時請求鎖L和鎖M的每一個執行緒,都是按照從 L 到 M 的順序,那麼就不會發生死鎖了。
  比如:銀行賬戶轉賬問題,兩個使用者轉賬的話,如果採用一般的synchronized巢狀的話,容易造成死鎖。

思想

  我們可以制定鎖的順序,並在整個應用程式中,獲得鎖都必須始終遵守這個既定的順序。我們在制定物件順序的時候,可以使用System.identityHashCode這樣一種方式,它會返回Object.hashcode所返回的值。 在極少數的情況下,2個物件具有相同的雜湊碼,我們必須使用任意的中數來決定鎖的順序,這又重新引入了死鎖的可能性。這個時候我們使用另一個鎖(加時賽鎖),在獲得2個物件的鎖之前,就要獲得這個鎖。

/**
 * @program:
 * @description: 動態的鎖順序死鎖的解決方案——通過鎖順序來避免死鎖
 * @author: zhouzhixiang
 * @create: 2018-11-16 20:03
 */
public class ThreadTest5 {

    // 加時賽鎖
    private static final Object tieLock = new Object();

    class Account implements Comparable{
        String username;
        String password;
long moneycount; void debit(long amount) { moneycount = moneycount - amount; } void credit(long amount) { moneycount = moneycount + amount; } @Override public int compareTo(Object o) { return (int) (moneycount -
((long)o)); } } /** * 此方法容易發生動態的鎖順序死鎖——錯誤方式 * @param fromAccount 轉賬方 * @param toAccount 收賬方 * @param amount 轉賬金額 */ public void tranferMoney(Account fromAccount, Account toAccount, long amount) throws InsufficientResourcesException { synchronized(fromAccount) { synchronized (toAccount) { if(fromAccount.compareTo(amount) < 0) throw new InsufficientResourcesException(); else { fromAccount.debit(amount); toAccount.credit(amount); } } } } /** * 通過鎖順序來避免死鎖——正確方法 * @param fromAccount 轉賬方 * @param toAccount 收賬方 * @param amount 轉賬金額 */ public void tranferMoney2(Account fromAccount, Account toAccount, long amount) throws InsufficientResourcesException { class Helper { public void tranfer() throws InsufficientResourcesException { if(fromAccount.compareTo(amount) < 0) throw new InsufficientResourcesException(); else { fromAccount.debit(amount); toAccount.credit(amount); } } } int fromHashCode = System.identityHashCode(fromAccount); int toHashCode = System.identityHashCode(toAccount); if(fromHashCode < toHashCode) { synchronized (fromAccount) { synchronized (toAccount) { new Helper().tranfer(); } } }else if (fromHashCode > toHashCode) { synchronized (toAccount) { synchronized (fromAccount) { new Helper().tranfer(); } } }else { // 加時賽鎖 synchronized (tieLock) { synchronized (fromAccount) { synchronized (toAccount) { new Helper().tranfer(); } } } } } }

歡迎加入Java猿社群
歡迎加入Java猿社群.png