什麼情況下才會出現死鎖呢?一種比較典型的情況是:
有兩個線程,就叫做thread1 和thread2,這兩個線程的執行過程中都需要擷取資源A和資源B的鎖。當出現這種情況的時候,就會導緻兩個線程死鎖:
Thread1通路A資源,然後準備通路B資源,Thread2先通路B資源,然後準備通路A資源。當thread1和thread2同時執行的時候,就可能導緻死鎖。因為可能thread1一直沒法擷取到資源B的鎖,而Thread2也一直沒法擷取到資源A的鎖,就都卡在那裡,等待着擷取一個永遠擷取不到的鎖。
我們可以手寫一段會産生死鎖的代碼:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class DeadLockTest {
// private Object A = new Object();
// private Object B = new Object();
public static void main(String[] args) {
Lock A = new ReentrantLock();
Lock B = new ReentrantLock();
new Thread(){
public void run(){
System.out.println("Thread1 -- trying to get lock A");
A.lock();
System.out.println("Thread1 -- get lock A successfully!");
try {
sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread1 -- trying to get lock B");
B.lock();
System.out.println("Thread1 -- get lock B successfully!");
}
}.start();
new Thread(){
public void run(){
System.out.println("Thread2 -- trying to get lock B");
B.lock();
System.out.println("Thread2 -- get lock A successfully!");
try {
sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread2 -- trying to get lock A");
A.lock();
System.out.println("Thread2 -- get lock B successfully!");
}
}.start();
}
}
上面的邏輯很簡單,就是thread1和thread2都分别希望能夠得到A的鎖和B的鎖。但是有點不同的是thread1先獲得A鎖,然後接下來準備獲得B鎖。thread2希望做到同樣的事情,但是擷取鎖的順序是相反的,準備先獲得B鎖,然後獲得A鎖。
為了確定死鎖一定會發生,我讓每個線程在獲得第一個鎖之後,暫停半秒。果然最終結果和預想的一樣,結果如下:
Thread1 – trying to get lock A
Thread1 – get lock A successfully!
Thread2 – trying to get lock B
Thread2 – get lock A successfully!
Thread1 – trying to get lock B
Thread2 – trying to get lock A
最後thread1和thread2都卡在了擷取第二個鎖的地方,因為A鎖和B鎖此刻都已經被擷取,沒有被釋放,是以此刻是沒法擷取到鎖資源的。