當線程需要同時持有多個鎖時,有可能產生死鎖??紤]如下情形:
線程 A 當前持有互斥所鎖 lock1,線程 B 當前持有互斥鎖 lock2。接下來,當線程 A 仍然持有 lock1 時,它試圖獲取 lock2,因為線程 B 正持有 lock2,因此線程 A 會阻塞等待線程 B 對 lock2 的釋放。如果此時線程 B 在持有 lock2 的時候,也在試圖獲取 lock1,因為線程 A 正持有 lock1,因此線程 B 會阻塞等待 A 對 lock1 的釋放。二者都在等待對方所持有鎖的釋放,而二者卻又都沒釋放自己所持有的鎖,這時二者便會一直阻塞下去。這種情形稱為死鎖。
下面給出一個兩個線程間產生死鎖的示例,如下:
public class Deadlock extends Object {
private String objID;
public Deadlock(String id) {
objID = id;
}
public synchronized void checkOther(Deadlock other) {
print("entering checkOther()");
try { Thread.sleep(2000); }
catch ( InterruptedException x ) { }
print("in checkOther() - about to " + "invoke 'other.action()'");
//調用other對象的action方法,由于該方法是同步方法,因此會試圖獲取other對象的對象鎖
other.action();
print("leaving checkOther()");
}
public synchronized void action() {
print("entering action()");
try { Thread.sleep(500); }
catch ( InterruptedException x ) { }
print("leaving action()");
}
public void print(String msg) {
threadPrint("objID=" + objID + " - " + msg);
}
public static void threadPrint(String msg) {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + ": " + msg);
}
public static void main(String[] args) {
final Deadlock obj1 = new Deadlock("obj1");
final Deadlock obj2 = new Deadlock("obj2");
Runnable runA = new Runnable() {
public void run() {
obj1.checkOther(obj2);
}
};
Thread threadA = new Thread(runA, "threadA");
threadA.start();
try { Thread.sleep(200); }
catch ( InterruptedException x ) { }
Runnable runB = new Runnable() {
public void run() {
obj2.checkOther(obj1);
}
};
Thread threadB = new Thread(runB, "threadB");
threadB.start();
try { Thread.sleep(5000); }
catch ( InterruptedException x ) { }
threadPrint("finished sleeping");
threadPrint("about to interrupt() threadA");
threadA.interrupt();
try { Thread.sleep(1000); }
catch ( InterruptedException x ) { }
threadPrint("about to interrupt() threadB");
threadB.interrupt();
try { Thread.sleep(1000); }
catch ( InterruptedException x ) { }
threadPrint("did that break the deadlock?");
}
}
運行結果如下:
http://wiki.jikexueyuan.com/project/java-concurrency/images/deadlock.jpg" alt="" />
從結果中可以看出,在執(zhí)行到 other.action() 時,由于兩個線程都在試圖獲取對方的鎖,但對方都沒有釋放自己的鎖,因而便產生了死鎖,在主線程中試圖中斷兩個線程,但都無果。
大部分代碼并不容易產生死鎖,死鎖可能在代碼中隱藏相當長的時間,等待不常見的條件地發(fā)生,但即使是很小的概率,一旦發(fā)生,便可能造成毀滅性的破壞。避免死鎖是一件困難的事,遵循以下原則有助于規(guī)避死鎖: