亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

java 死鎖及解決

系統 1842 0

Java線程死鎖如何避免這一悲劇? Java線程死鎖需要如何解決,這個問題一直在我們不斷的使用中需要只有不斷的關鍵。不幸的是,使用上鎖會帶來其他問題。讓我們來看一些常見問題以及相應的解決方法:

  Java線程死鎖

  Java線程死鎖是一個經典的多線程問題,因為不同的線程都在等待那些根本不可能被釋放的鎖,從而導致所有的工作都無法完成。假設有兩個線程,分別代表兩個饑餓的人,他們必須共享刀叉并輪流吃飯。他們都需要獲得兩個鎖:共享刀和共享叉的鎖。

  假如線程 “A”獲得了刀,而線程“B”獲得了叉。線程“A”就會進入阻塞狀態來等待獲得叉,而線程“B”則阻塞來等待“A”所擁有的刀。這只是人為設計的例子,但盡管在運行時很難探測到,這類情況卻時常發生。 雖然要探測或推敲各種情況是非常困難的,但只要按照下面幾條規則去設計系統,就能夠避免Java線程死鎖問題:

讓所有的線程按照同樣的順序獲得一組鎖。這種方法消除了 X 和 Y 的擁有者分別等待對方的資源的問題。

將多個鎖組成一組并放到同一個鎖下。前面Java線程死鎖的例子中,可以創建一個銀器對象的鎖。于是在獲得刀或叉之前都必須獲得這個銀器的鎖。

  將那些不會阻塞的可獲得資源用變量標志出來。當某個線程獲得銀器對象的鎖時,就可以通過檢查變量來判斷是否整個銀器集合中的對象鎖都可獲得。如果是,它就可以獲得相關的鎖,否則,就要釋放掉銀器這個鎖并稍后再嘗試。

?

  最重要的是,在編寫代碼前認真仔細地設計整個系統。多線程是困難的,在開始編程之前詳細設計系統能夠幫助你避免難以發現Java線程死鎖的問題。

?

  Volatile 變量,volatile 關鍵字是 Java 語言為優化編譯器設計的。以下面的代碼為例:

  1.class VolatileTest {

  2.public void foo() {

  3.boolean flag = false;

  4.if(flag) {

  5.//this could happen

  6.}

  7.}

  8.}

  一個優化的編譯器可能會判斷出if部分的語句永遠不會被執行,就根本不會編譯這部分的代碼。如果這個類被多線程訪問, flag被前面某個線程設置之后,在它被if語句測試之前,可以被其他線程重新設置。用volatile關鍵字來聲明變量,就可以告訴編譯器在編譯的時候,不需要通過預測變量值來優化這部分的代碼。

  無法訪問的Java線程死鎖有時候雖然獲取對象鎖沒有問題,線程依然有可能進入阻塞狀態。在 Java 編程中IO就是這類問題最好的例子。當線程因為對象內的IO調用而阻塞時,此對象應當仍能被其他線程訪問。該對象通常有責任取消這個阻塞的IO操作。造成阻塞調用的線程常常會令同步任務失敗。如果該對象的其他方法也是同步的,當線程被阻塞時,此對象也就相當于被冷凍住了。

  其他的線程由于不能獲得對象的Java線程死鎖,就不能給此對象發消息(例如,取消 IO 操作)。必須確保不在同步代碼中包含那些阻塞調用,或確認在一個用同步阻塞代碼的對象中存在非同步方法。盡管這種方法需要花費一些注意力來保證結果代碼安全運行,但它允許在擁有對象的線程發生阻塞后,該對象仍能夠響應其他線程。

=======================================================================

死鎖是這樣一種情形:多個線程同時被阻塞,它們中的一個或者全部都在等待某個資源被釋放。由于線程被無限期地阻塞,因此程序不可能正常終止。 ?

? ? 導致死鎖的根源在于不適當地運用“synchronized”關鍵詞來管理線程對特定對象的訪問。 “synchronized”關鍵詞的作用是,確保在某個時刻只有一個線程被允許執行特定的代碼塊,因此,被允許執行的線程首先必須擁有對變量或對象的排他性的訪問權。當線程訪問對象時,線程會給對象加鎖,而這個鎖導致其它也想訪問同一對象的線程被阻塞,直至第一個線程釋放它加在對象上的鎖。 ?

? 由于這個原因,在使用“synchronized”關鍵詞時,很容易出現兩個線程互相等待對方做出某個動作的情形。代碼一是一個導致死鎖的簡單例子。 ?

//代碼一

Java代碼 ? 復制代碼
  1. class ?Deadlocker?{ ??
  2. ? int ?field_1; ??
  3. ? private ?Object?lock_1?=? new ? int [ 1 ]; ??
  4. ? int ?field_2; ??
  5. ? private ?Object?lock_2?=? new ? int [ 1 ]; ??
  6. ??
  7. ? public ? void ?method1( int ?value)?{ ??
  8. ??“ synchronized ”?(lock_1)?{ ??
  9. ???“ synchronized ”?(lock_2)?{ ??
  10. ????field_1?=? 0 ;?field_2?=? 0 ; ??
  11. ???} ??
  12. ??} ??
  13. ?} ??
  14. ??
  15. ? public ? void ?method2( int ?value)?{ ??
  16. ??“ synchronized ”?(lock_2)?{ ??
  17. ???“ synchronized ”?(lock_1)?{ ??
  18. ????field_1?=? 0 ;?field_2?=? 0 ; ??
  19. ???} ??
  20. ??} ??
  21. ?} ??
  22. } ??
  23. ???
Java代碼
  1. class ?Deadlocker?{??
  2. ? int ?field_1;??
  3. ? private ?Object?lock_1?=? new ? int [ 1 ];??
  4. ? int ?field_2;??
  5. ? private ?Object?lock_2?=? new ? int [ 1 ];??
  6. ??
  7. ? public ? void ?method1( int ?value)?{??
  8. ??“ synchronized ”?(lock_1)?{??
  9. ???“ synchronized ”?(lock_2)?{??
  10. ????field_1?=? 0 ;?field_2?=? 0 ;??
  11. ???}??
  12. ??}??
  13. ?}??
  14. ??
  15. ? public ? void ?method2( int ?value)?{??
  16. ??“ synchronized ”?(lock_2)?{??
  17. ???“ synchronized ”?(lock_1)?{??
  18. ????field_1?=? 0 ;?field_2?=? 0 ;??
  19. ???}??
  20. ??}??
  21. ?}??
  22. }??
  23. ???



? 參考代碼一,考慮下面的過程: ?

? ◆ 一個線程(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兩個鎖,即線程獲取兩個鎖的過程沒有被中斷。在這種情形下,常規的死鎖檢測很難確定錯誤所在。 ?

? 占有并等待 ?

? 如果一個線程獲得了一個鎖之后還要等待來自另一個線程的通知,可能出現另一種隱性死鎖,考慮代碼二。 ?

//代碼二

Java代碼 ? 復制代碼
  1. public ? class ?queue?{ ??
  2. ? static ?java.lang.Object?queueLock_; ??
  3. ?Producer?producer_; ??
  4. ?Consumer?consumer_; ??
  5. ??
  6. ? public ? class ?Producer?{ ??
  7. ?? void ?produce()?{ ??
  8. ??? while ?(!done)?{ ??
  9. ????“ synchronized ”?(queueLock_)?{ ??
  10. ?????produceItemAndAddItToQueue(); ??
  11. ?????“ synchronized ”?(consumer_)?{ ??
  12. ??????consumer_.notify(); ??
  13. ?????} ??
  14. ????} ??
  15. ???} ??
  16. ??} ??
  17. ??
  18. ?? public ? class ?Consumer?{ ??
  19. ???consume()?{ ??
  20. ???? while ?(!done)?{ ??
  21. ?????“ synchronized ”?(queueLock_)?{ ??
  22. ??????“ synchronized ”?(consumer_)?{ ??
  23. ???????consumer_.wait(); ??
  24. ??????} ??
  25. ??????removeItemFromQueueAndProcessIt(); ??
  26. ?????} ??
  27. ????} ??
  28. ???} ??
  29. ??} ??
  30. ?} ??
  31. } ??
  32. ???
Java代碼
  1. public ? class ?queue?{??
  2. ? static ?java.lang.Object?queueLock_;??
  3. ?Producer?producer_;??
  4. ?Consumer?consumer_;??
  5. ??
  6. ? public ? class ?Producer?{??
  7. ?? void ?produce()?{??
  8. ??? while ?(!done)?{??
  9. ????“ synchronized ”?(queueLock_)?{??
  10. ?????produceItemAndAddItToQueue();??
  11. ?????“ synchronized ”?(consumer_)?{??
  12. ??????consumer_.notify();??
  13. ?????}??
  14. ????}??
  15. ???}??
  16. ??}??
  17. ??
  18. ?? public ? class ?Consumer?{??
  19. ???consume()?{??
  20. ???? while ?(!done)?{??
  21. ?????“ synchronized ”?(queueLock_)?{??
  22. ??????“ synchronized ”?(consumer_)?{??
  23. ???????consumer_.wait();??
  24. ??????}??
  25. ??????removeItemFromQueueAndProcessIt();??
  26. ?????}??
  27. ????}??
  28. ???}??
  29. ??}??
  30. ?}??
  31. }??
  32. ???




? 在代碼二中, Producer向隊列加入一項新的內容后通知Consumer,以便它處理新的內容。問題在于,Consumer可能保持加在隊列上的鎖,阻止Producer訪問隊列,甚至在Consumer等待Producer的通知時也會繼續保持鎖。這樣,由于Producer不能向隊列添加新的內容,而Consumer卻在等待Producer加入新內容的通知,結果就導致了死鎖。 ?

? 在等待時占有的鎖是一種隱性的死鎖,這是因為事情可能按照比較理想的情況發展—Producer線程不需要被Consumer占據的鎖。盡管如此,除非有絕對可靠的理由肯定Producer線程永遠不需要該鎖,否則這種編程方式仍是不安全的。有時“占有并等待”還可能引發一連串的線程等待,例如,線程A占有線程B需要的鎖并等待,而線程B又占有線程C需要的鎖并等待等。 ?

? 要改正代碼二的錯誤,只需修改Consumer類,把wait()移出“synchronized”()即可。 ?

? 因此避免死鎖的一個通用的經驗法則是:當幾個線程都要訪問共享資源A、B、C時,保證使每個線程都按照同樣的順序去訪問它們,比如都先訪問A,在訪問B和C。 ?
? 此外,Thread類的suspend()方法也很容易導致死鎖,因此這個方法已經被廢棄了.

轉自: http://leowzy.iteye.com/blog/740859

java 死鎖及解決


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产探花一区 | 天天做天天爱夜夜大爽完整 | 99久久精品免费看国产免费 | 黄毛片网站| 日韩一区二区视频 | 久久久久在线观看 | 国产高清一区二区三区免费视频 | 五月国产综合视频在线观看 | 成人欧美精品大91在线 | 精品国产免费观看久久久 | 五月天婷婷在线观看高清 | 亚欧洲精品bb | 亚洲精品免费在线视频 | 四虎影院视频在线观看 | 亚洲精品一区久久狠狠欧美 | xx毛片| 久久久毛片免费全部播放 | 青青爽国产手机在线观看免费 | 人人骚| 伊人色综合网 | 欧美成人看片 | 一区二区三区在线播放视频 | jizzjizzjizz孕妇| 久久久久久久国产免费看 | 国产一区二区三区不卡观 | 91在线视频观看 | 欧美国产亚洲18 | 亚洲欧洲精品在线 | 国产一区二区三区乱码网站 | 日本一级爰免费视频 | 精品看片 | 日本一线一区二区三区免费视频 | 日本aⅴ在线 | 97在线免费 | 激情五月综合网 | 日韩精品中文字幕一区三区 | 综合图区亚洲白拍在线 | 天天做天天做天天综合网 | 全免费一级毛片在线播放 | 一级毛片视频免费 | 麻豆久久精品免费看国产 |