【Java并發(fā)編程】之九:死鎖(含代碼)
來源:程序員人生 發(fā)布時間:2015-04-15 09:08:27 閱讀次數(shù):3211次
當線程需要同時持有多個鎖時,有可能產(chǎn)生死鎖。斟酌以下情形:
線程A當前持有互斥所鎖lock1,線程B當前持有互斥鎖lock2。接下來,當線程A依然持有l(wèi)ock1時,它試圖獲得lock2,由于線程B正持有l(wèi)ock2,因此線程A會阻塞等待線程B對lock2的釋放。如果此時線程B在持有l(wèi)ock2的時候,也在試圖獲得lock1,由于線程A正持有l(wèi)ock1,因此線程B會阻塞等待A對lock1的釋放。2者都在等待對方所持有鎖的釋放,而2者卻又都沒釋放自己所持有的鎖,這時候2者便會1直阻塞下去。這類情形稱為死鎖。
下面給出1個兩個線程間產(chǎn)生死鎖的示例,以下:
-
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();
-
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?");
-
}
-
}
運行結果以下:

從結果中可以看出,在履行到other.action()時,由于兩個線程都在試圖獲得對方的鎖,但對方都沒有釋放自己的鎖,因此便產(chǎn)生了死鎖,在主線程中試圖中斷兩個線程,但都無果。
大部份代碼其實不容易產(chǎn)生死鎖,死鎖可能在代碼中隱藏相當長的時間,等待不常見的條件地產(chǎn)生,但即便是很小的幾率,1旦產(chǎn)生,即可能造成毀滅性的破壞。避免死鎖是1件困難的事,遵守以下原則有助于規(guī)避死鎖:
1、只在必要的最短時間內持有鎖,斟酌使用同步語句塊代替全部同步方法;
2、盡可能編寫不在同1時刻需要持有多個鎖的代碼,如果不可避免,則確保線程持有第2個鎖的時間盡可能短暫;
3、創(chuàng)建和使用1個大鎖來代替若干小鎖,并把這個鎖用于互斥,而不是用作單個對象的對象級別鎖;
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學習有所幫助,可以手機掃描二維碼進行捐贈