巷尾的酒吧

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            64 Posts :: 0 Stories :: 5 Comments :: 0 Trackbacks
          死鎖     死鎖是這樣一種情形:多個線程同時被阻塞,它們中的一個或者全部都在等待某個資源被釋放。由于線程被無限期地阻塞,因此程序不可能正常終止。     導致死鎖的根源在于不適當地運用“synchronized”關鍵詞來管理線程對特定對象的訪問。“synchronized”關鍵詞的作用是,確保在某個時刻只有一個線程被允許執行特定的代碼塊,因此,被允許執行的線程首先必須擁有對變量或對象的排他性的訪問權。當線程訪問對象時,線程會給對象加鎖,而這個鎖導致其它也想訪問同一對象的線程被阻塞,直至第一個線程釋放它加在對象上的鎖。     由于這個原因,在使用“synchronized”關鍵詞時,很容易出現兩個線程互相等待對方做出某個動作的情形。代碼一是一個導致死鎖的簡單例子。   //代碼一 class Deadlocker {  int field_1;  private Object lock_1 = new int[1];  int field_2;  private Object lock_2 = new int[1];   public void method1(int value) {   “synchronized” (lock_1) {    “synchronized” (lock_2) {     field_1 = 0; field_2 = 0;    }   }  }   public void method2(int value) {   “synchronized” (lock_2) {    “synchronized” (lock_1) {     field_1 = 0; field_2 = 0;    }   }  } }       參考代碼一,考慮下面的過程:     ◆ 一個線程(ThreadA)調用method1()。     ◆ ThreadA在lock_1上同步,但允許被搶先執行。     ◆ 另一個線程(ThreadB)開始執行。     ◆ ThreadB調用method2()。     ◆ ThreadB獲得lock_2,繼續執行,企圖獲得lock_1。但ThreadB不能獲得lock_1,因為ThreadA占有lock_1。     ◆ 現在,ThreadB阻塞,因為它在等待ThreadA釋放lock_1。     ◆ 現在輪到ThreadA繼續執行。ThreadA試圖獲得lock_2,但不能成功,因為lock_2已經被ThreadB占有了。     ◆ ThreadA和ThreadB都被阻塞,程序死鎖。     當然,大多數的死鎖不會這么顯而易見,需要仔細分析代碼才能看出,對于規模較大的多線程程序來說尤其如此。好的線程分析工具,例如JProbe Threadalyzer能夠分析死鎖并指出產生問題的代碼位置。     隱性死鎖     隱性死鎖由于不規范的編程方式引起,但不一定每次測試運行時都會出現程序死鎖的情形。由于這個原因,一些隱性死鎖可能要到應用正式發布之后才會被發現,因此它的危害性比普通死鎖更大。下面介紹兩種導致隱性死鎖的情況:加鎖次序和占有并等待。     加鎖次序     當多個并發的線程分別試圖同時占有兩個鎖時,會出現加鎖次序沖突的情形。如果一個線程占有了另一個線程必需的鎖,就有可能出現死鎖??紤]下面的情形,ThreadA和ThreadB兩個線程分別需要同時擁有lock_1、lock_2兩個鎖,加鎖過程可能如下:     ◆ ThreadA獲得lock_1;     ◆ ThreadA被搶占,VM調度程序轉到ThreadB;     ◆ ThreadB獲得lock_2;     ◆ ThreadB被搶占,VM調度程序轉到ThreadA;     ◆ ThreadA試圖獲得lock_2,但lock_2被ThreadB占有,所以ThreadA阻塞;     ◆ 調度程序轉到ThreadB;     ◆ ThreadB試圖獲得lock_1,但lock_1被ThreadA占有,所以ThreadB阻塞;     ◆ ThreadA和ThreadB死鎖。     必須指出的是,在代碼絲毫不做變動的情況下,有些時候上述死鎖過程不會出現,VM調度程序可能讓其中一個線程同時獲得lock_1和lock_2兩個鎖,即線程獲取兩個鎖的過程沒有被中斷。在這種情形下,常規的死鎖檢測很難確定錯誤所在。     占有并等待     如果一個線程獲得了一個鎖之后還要等待來自另一個線程的通知,可能出現另一種隱性死鎖,考慮代碼二。   //代碼二 public class queue {  static java.lang.Object queueLock_;  Producer producer_;  Consumer consumer_;   public class Producer {   void produce() {    while (!done) {     “synchronized” (queueLock_) {      produceItemAndAddItToQueue();      “synchronized” (consumer_) {       consumer_.notify();      }     }    }   }    public class Consumer {    consume() {     while (!done) {      “synchronized” (queueLock_) {       “synchronized” (consumer_) {        consumer_.wait();       }       removeItemFromQueueAndProcessIt();      }     }    }   }  } }       在代碼二中,Producer向隊列加入一項新的內容后通知Consumer,以便它處理新的內容。問題在于,Consumer可能保持加在隊列上的鎖,阻止Producer訪問隊列,甚至在Consumer等待Producer的通知時也會繼續保持鎖。這樣,由于Producer不能向隊列添加新的內容,而Consumer卻在等待Producer加入新內容的通知,結果就導致了死鎖。     在等待時占有的鎖是一種隱性的死鎖,這是因為事情可能按照比較理想的情況發展—Producer線程不需要被Consumer占據的鎖。盡管如此,除非有絕對可靠的理由肯定Producer線程永遠不需要該鎖,否則這種編程方式仍是不安全的。有時“占有并等待”還可能引發一連串的線程等待,例如,線程A占有線程B需要的鎖并等待,而線程B又占有線程C需要的鎖并等待等。     要改正代碼二的錯誤,只需修改Consumer類,把wait()移出“synchronized”()即可。
          posted on 2012-10-17 15:48 abing 閱讀(325) 評論(0)  編輯  收藏 所屬分類: thread

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 资阳市| 屏东市| 嘉峪关市| 隆林| 特克斯县| 安丘市| 东海县| 莎车县| 青阳县| 斗六市| 长阳| 全椒县| 三台县| 乐至县| 禹州市| 嘉禾县| 岢岚县| 广西| 芒康县| 白银市| 闻喜县| 洪洞县| 偃师市| 枣阳市| 绥宁县| 陈巴尔虎旗| 班玛县| 剑河县| 建阳市| 西宁市| 浠水县| 唐山市| 遂溪县| 鸡西市| 亚东县| 行唐县| 新河县| 盐山县| 鸡东县| 平定县| 松潘县|