zoukankan      html  css  js  c++  java
  • 第10章避免活跃性危险

    如果每个需要锁L和锁M的线程都以相同的顺序来获取L和M,那么就不会发生死锁了。

    解决这个问题,必须定义锁的顺序,并在整个应用程序中都按照这个顺序来获取锁。

    在制定锁的顺序时,可以使用System.identityHashCode方法,该方法将返回由Object.hashCode返回的值。

        private static final Object tieLock = new Object();
        
        public void transferMoney(final Account fromAcct,
                                  final Account toAcct,
                                  final DollarAmount amount) 
            throws InsufficientFundsException {
            class Helper {
                public void transfer() throws InsufficientFundsException {
                    if (fromAcct.getBalance().compareTo(amount) < 0) {
                        throw new InsufficientFundsException();
                    } else {
                        fromAcct.debit(amount);
                        toAcct.credit(amount);
                    }
                }
            }
            int fromHash = System.identityHashCode(fromAcct);
            int toHash = System.identityHashCode(toAcct);
            
            if (fromHash < toHash) {
                synchronized (fromAcct) {
                    synchronized (toAcct) {
                        new Helper().transfer();
                    }
                }
            }
            else if (fromHash > toHash) {
                synchronized (toAcct) {
                    synchronized (fromAcct) {
                        new Helper().transfer();
                    }
                }
            }
            else {
                synchronized (tieLock) {
                    synchronized (fromAcct) {
                        synchronized (toAcct) {
                            new Helper().transfer();
                        }
                    }
                }
            }
        }

    在极少数情况下,两个对象可能拥有相同的散列值,此时必须通过某种任意的方法来决定锁的顺序,而这可能又会重新引入死锁。为了避免这种情况,可以使用“加时赛(TieBreaking)”锁。在获得两个Account锁之前,首先获得这个“加时赛”锁,从而保证每次只有一个线程以未知的顺序获得这两个锁,从而消除了死锁发生的可能性(只要一致地使用这种机制)。如果经常会出现散列冲突的情况,那么这种技术可能会成为并发性的一个瓶颈(这类似于在整个程序中只有一个锁的情况),但由于System.identityHashCode中出现散列冲突的频率非常低,因此这项技术以最小的代价,换来了最大的安全性。

    如果在调用某个方法时不需要持有锁,那么这种调用被称为开放调用(Open Call)。

    在程序中尽量使用开放调用。与那些在持有锁时调用外部方法的程序相比,更易于对依赖开放调用的程序进行死锁分析。

    要避免使用线程优先级,因为这会增加平台依赖性,并可能导致活跃性问题。在大多数并发应用程序中,都可以使用默认的线程优先级。

  • 相关阅读:
    LeetCode Best Time to Buy and Sell Stock
    LeetCode Scramble String
    LeetCode Search in Rotated Sorted Array II
    LeetCode Gas Station
    LeetCode Insertion Sort List
    LeetCode Maximal Rectangle
    Oracle procedure
    浏览器下载代码
    Shell check IP
    KVM- 存储池配置
  • 原文地址:https://www.cnblogs.com/a0000/p/4903364.html
Copyright © 2011-2022 走看看