Java鎖——死鎖
死鎖
死鎖是這樣一種情形:多個執行緒同時被阻塞,它們中的一個或者全部都在等待某個資源被釋放。由於執行緒被無限期地阻塞,因此程式不可能正常終止。
產生條件
java 死鎖產生的四個必要條件:
1、互斥使用,即當資源被一個執行緒使用(佔有)時,別的執行緒不能使用
2、不可搶佔,資源請求者不能強制從資源佔有者手中奪取資源,資源只能由資源佔有者主動釋放。
3、請求和保持,即當資源請求者在請求其他的資源的同時保持對原有資源的佔有。
4、迴圈等待,即存在一個等待佇列:P1佔有P2的資源,P2佔有P3的資源,P3佔有P1的資源。這樣就形成了一個等待環路。
當上述四個條件都成立的時候,便形成死鎖。當然,死鎖的情況下如果打破上述任何一個條件,便可讓死鎖消失。
死鎖示例
有兩個共享資源object1,object2,我們知道每個物件內部都有一個監視器鎖,當一個執行緒佔有資源 object1,保持不釋放,並申請資源 object2;而另一個執行緒佔有資源 object2,保持不釋放,並申請資源 object1;這樣就會導致兩個執行緒一直在迴圈等待,產生死鎖。
/**
* ClassName: MyDeadLock <br/>
* Function: 死鎖示例<br/>
*
* @author gary.liu
* @date 2017/6/24
*/
public class MyDeadLock {
private static Object object1 = new Object();
private static Object object2 = new Object();
private static CountDownLatch countDownLatch = new CountDownLatch(1);
static class Worker implements Runnable {
public void run() {
synchronized (object1) {
System.out.println("Worker has object1 lock!");
/**
*
* 不睡一會的話,由於兩個執行緒的執行時間可能不是同時的,就會有一個先執行,獲取兩個資源後釋放,一個後執行,此時可能不會產生死鎖;
* 如果執行緒幾乎同時開始執行,則就有可能產生死鎖,加這個 sleep 時間就是讓死鎖產生的更明顯.
*
* 為了證明上面的說法,使用 CountDownLatch 讓兩個執行緒同時執行來看看結果
*
*/
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object2) {
//由於產生死鎖,無法輸出
System.out.println("Worker has object2 lock!");
}
}
}
}
static class Boss implements Runnable {
public void run() {
synchronized (object2) {
System.out.println("Boss has object2 lock!");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object1) {
//由於產生死鎖,無法輸出
System.out.println("Boss has object1 lock!");
}
}
}
}
public static void main(String[] args) throws Exception{
Thread worker = new Thread(new Worker());
Thread boss = new Thread(new Boss());
worker.start();
boss.start();
}
}
執行結果
Worker has object1 lock!
Boss has object2 lock!
//兩個執行緒一直在迴圈等待獲取對方資源,產生死鎖,程式還一直在執行,但沒有內容輸出了
程式碼中的註釋:
不睡一會的話,由於兩個執行緒的執行時間可能不是同時的,就會有一個先執行,一個後執行,此時可能不會產生死鎖;如果執行緒幾乎同時開始執行,則就有可能產生死鎖,加這個等待時間就是讓死鎖更有機會產生. 為了證明上面的說法,使用 CountDownLatch 讓兩個執行緒同時執行來看看結果,不用 sleep 一會,基本每次都會產生死鎖。
兩個執行緒同時執行,加大產生死鎖的機會
public class MyDeadLock {
private static Object object1 = new Object();
private static Object object2 = new Object();
private static CountDownLatch countDownLatch = new CountDownLatch(1);
static class Worker implements Runnable {
public void run() {
synchronized (object1) {
try {
countDownLatch.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
System.out.println("Worker has object1 lock!");
synchronized (object2) {
//由於產生死鎖,無法輸出
System.out.println("Worker has object2 lock!");
}
}
}
}
static class Boss implements Runnable {
public void run() {
synchronized (object2) {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Boss has object2 lock!");
synchronized (object1) {
//由於產生死鎖,無法輸出
System.out.println("Boss has object1 lock!");
}
}
}
}
public static void main(String[] args) throws Exception{
Thread worker = new Thread(new Worker());
Thread boss = new Thread(new Boss());
//因為用countDownLatch.await();兩個執行緒被阻塞了
worker.start();
boss.start();
//更清楚的看到 worker,boss 執行緒被阻塞
Thread.sleep(3000);
//之後兩個執行緒開始同時繼續執行,基本每次都會產生死鎖
countDownLatch.countDown();
}
}
分析死鎖
1、jps
檢視程式程式 id,即 pid
2、jstack pid
列印堆疊資訊,可以從堆疊資訊中看到 Thread-1 和 Thread-0 在互相等待對方釋放資源。
具體分析參考:Java多執行緒7:死鎖
或者用 jdk 自帶的命令 jvisualvm
工具,對程式的執行進行監控,可以看到執行緒監控中已經檢測到死鎖,如下圖。
避免死鎖
破壞上面產生死鎖的四個必要條件
遵循以下原則有助於規避死鎖:
1、只在必要的最短時間內持有鎖,考慮使用同步語句塊代替整個同步方法;
2、儘量編寫不在同一時刻需要持有多個鎖的程式碼,如果不可避免,則確保執行緒持有第二個鎖的時間儘量短暫;
3、建立和使用一個大鎖來代替若干小鎖,並把這個鎖用於互斥,而不是用作單個物件的物件級別鎖;
4、破壞迴圈等待條件,可以使用 Lock 類中的 tryLock 方法去嘗試獲取鎖,這個方法可以指定一個超時時限,在等待超過該時限之後變回返回一個失敗資訊;也可以使用訊號量,指定去獲取的超時時間。
參考資料
相關文章
- 例項詳解 Java 死鎖與破解死鎖Java
- Java 中的死鎖Java
- java如何避免程式死鎖Java
- [Java併發]避免死鎖Java
- 死鎖
- Java中常見死鎖與活鎖的例項Java
- 死鎖和可重入鎖
- MySQL 死鎖和鎖等待MySql
- java中死鎖是什麼Java
- 什麼是死鎖?如何解決死鎖?
- 面試官:什麼是死鎖?怎麼排查死鎖?怎麼避免死鎖?面試
- 死鎖概述
- SQL SERVER死鎖查詢,死鎖分析,解鎖,查詢佔用SQLServer
- 作業系統(5) 死鎖的概念 死鎖產生的必要條件 死鎖的處理策略 預防死鎖 避免死鎖 死鎖的檢測和解除 銀行家演算法作業系統演算法
- 檢視oracle死鎖程式並結束死鎖Oracle
- Java多執行緒(五):死鎖Java執行緒
- java多執行緒(5)死鎖Java執行緒
- 面試:什麼是死鎖,如何避免或解決死鎖;MySQL中的死鎖現象,MySQL死鎖如何解決面試MySql
- MySQL死鎖系列-線上死鎖問題排查思路MySql
- 死鎖是什麼?如何預防和避免死鎖?
- 如何避免死鎖和活鎖? - simar
- SQLServer的死鎖分析(1):頁鎖SQLServer
- mysql行鎖和死鎖檢測MySql
- 鎖的使用與死鎖的避免
- Mysql 兩階段鎖和死鎖MySql
- GCD 死鎖原因GC
- 死鎖案例二
- 死鎖案例三
- 併發:死鎖
- 遭遇ITL死鎖
- 死鎖-舉例
- 死鎖案例分析
- java多執行緒中的死鎖、活鎖、飢餓、無鎖都是什麼鬼?Java執行緒
- MySQL:一個死鎖分析 (未分析出來的死鎖)MySql
- MySQL鎖等待與死鎖問題分析MySql
- MySQL/InnoDB中,樂觀鎖、悲觀鎖、共享鎖、排它鎖、行鎖、表鎖、死鎖概念的理解MySql
- java安全編碼指南之:死鎖dead lockJava
- Java面試必問-死鎖終極篇Java面試
- MySQL 死鎖解決MySql