死鎖

1、順序死鎖

private static final String LEFT = "left";
    private static final String RIGHT = "right";


    public static void main(String[] args) throws Exception {
        Thread deallock1 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    synchronized (LEFT) {
                        synchronized (RIGHT) {
                            System.out.printf("todo1");
                        }
                    }
                }
            }
        });
        Thread deallock2 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    synchronized (RIGHT) {
                        synchronized (LEFT) {
                            System.out.printf("todo2");
                        }
                    }
                }
            }
        });
        deallock1.setName("deallock1");
        deallock2.setName("deallock2");
        deallock1.start();
        deallock2.start();
    }

2、動態順序死鎖

public static void transfer(Account from, Account to, int cash) throws Exception {
        synchronized (from) {
            synchronized (to) {
                from.money -= cash;
                to.money += cash;
            }
        }
    }

這段代碼看起來很良好,可是若是狀況是兩個線程一個transfer(my, your, cash),另外一個是transfer(your, my, cash)的時候,就會可能產生死鎖。若是可以保證上述的鎖的順序一致的話,就能避免死鎖,有一種方式能夠避免,就是比較對象的hashcode值,而後按照大小順序鎖住:java

3、資源競爭致使死鎖

  • 資源等待致使:好比一個數據庫鏈接池,一個線程須要兩個鏈接來完成任務,而後線程A獲取了鏈接1,線程B獲取了鏈接2,當鏈接池資源不足時,線程A想要繼續獲取鏈接2來完成任務,這時線程B也想要獲取鏈接1來完成任務,這時候發生死鎖。
  • 線程飢餓致使:一我的依賴另一個任務執行的結果,這種特別容易發生死鎖,要注意。

4、避免鎖的競爭

  1. 縮小鎖的範圍。如一個方法裏只有一個操做會引起數據不安全性,那就應該只在那個操做上下鎖住,而不該該鎖住整個方法。
  2. 減少鎖的粒度。如一個對象裏有多個須要共享的數據,那能夠考慮對各個變量加上鎖,防止一個方法只操做一個變量時,而鎖住了整個對象。
  3. 分段鎖。例如concurrentHashMap,將一個map劃分紅默認16個segment,就是一整個對象加了16個鎖。優勢是當獲取數據或修改數據時,不須要鎖住整個對象,而只須要鎖住裏面的一個table,這樣會下降鎖持有的時間。缺點是:好比從新計算散列鍵值分佈的時候,須要鎖住整個對象,就是一次性持有16個鎖,開銷很大。
相關文章
相關標籤/搜索