Java死鎖,你學(xué)會了嗎?
死鎖
死鎖是指兩個或兩個以上的進(jìn)程在執(zhí)行過程中,由于競爭資源或者由于彼此通信而造成的一種阻塞的現(xiàn)象,若無外力作用,他們都無法推進(jìn)下去。通俗一點就是兩個進(jìn)程都持有資源,但是又想搶對方的資源,互不相讓了。
圖片
死鎖的問題和其他的并發(fā)安全問題一樣,是概率性的,也就是說,即使存在發(fā)生死鎖的可能性,也并不是 100% 會發(fā)生的。如果每個鎖的持有時間很短,那么發(fā)生沖突的概率就很低,所以死鎖發(fā)生的概率也很低??赡苊刻煊袔浊f次的“獲取鎖”、“釋放鎖”操作,在巨量的次數(shù)面前,整個系統(tǒng)發(fā)生問題的幾率就會被放大。
必然死鎖例子
public static void main(String[] args) {
//2個對象2把鎖
//創(chuàng)建2個線程,首先獲取自己的對象鎖,確保獲取了鎖,然后去獲取對方的鎖
final Object o1 = new Object();
final Object o2 = new Object();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (o1) {
System.out.println("thread1獲取了o1對象的鎖");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread1等待o2鎖釋放...");
synchronized (o2) {
System.out.println("thread1獲取了o2對象的鎖");
}
}
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (o2) {
System.out.println("thread2獲取了o2對象的鎖");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread2等待o1鎖釋放...");
synchronized (o1) {
System.out.println("thread2獲取了o1對象的鎖");
}
}
}
});
thread1.start();
thread2.start();
}
運行結(jié)果:
thread1獲取了o1對象的鎖
thread2獲取了o2對象的鎖
thread2等待o1鎖釋放...
thread1等待o2鎖釋放...
可見線程一先上了o1鎖,線程二先上了o2鎖,然后線程一需要等待線程二的o2鎖釋放獲取到該鎖執(zhí)行完后續(xù)代碼才能釋放o1鎖,但線程二也需要等待線程一的o1鎖釋放獲取到該鎖執(zhí)行完后續(xù)代碼才能釋放o2鎖。他倆就互相等待,鎖死了。
死鎖必要條件
- 互斥:一個資源每次只能被一個進(jìn)程使用。
- 請求與保持:一個進(jìn)程因請求資源而阻塞時,對已獲得的資源保持不放。
- 不剝奪:進(jìn)程已獲得的資源,在末使用完之前,不能強(qiáng)行剝奪。
- 循環(huán)等待:若干進(jìn)程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系。
避免死鎖
加鎖順序(線程按照一定的順序加鎖,規(guī)定獲取資源需要按照一定順序)
加鎖時限(線程嘗試獲取鎖的時候加上一定的時限,超過時限則放棄對該鎖的請求,并釋放自己占有的鎖;第二,可以用Lock中tryLock,嘗試拿鎖,拿不到不會持續(xù)等待)
死鎖檢測