死鎖的四個必要條件
1)互斥條件蘑辑,即某個資源在一段時間內(nèi)只能由一個線程占有,不能同時被兩個或兩個以上的線程占有
2)不可搶占條件坠宴,線程所獲得的資源在未使用完畢之前洋魂,資源申請者不能強(qiáng)行地從資源占有者手中奪取資源,而只能由該資源的占有者線程自行釋放
3)占有且申請條件喜鼓,線程至少已經(jīng)占有一個資源副砍,但又申請新的資源;由于該資源已被另外線程占有庄岖,此時該線程阻塞豁翎;但是,它在等待新資源之時隅忿,仍繼續(xù)占用已占有的資源心剥。
4)循環(huán)等待條件,存在一個線程等待序列{P1背桐,P2优烧,...,Pn}链峭,其中P1等待P2所占有的某一資源畦娄,P2等待P3所占有的某一源,......弊仪,而Pn等待P1所占有的的某一資源熙卡,形成一個線程循環(huán)等待環(huán)
解決死鎖的辦法:加鎖順序,死鎖檢測
下面通過代碼實(shí)例來講解一下如何去寫一個死鎖代碼&如何去解決死鎖問題
public class DeadLockTest {
static class MyTask implements Runnable {
Object obj1 = "obj1";
Object obj2 = "obj2";
int flag;
private void setFlag(int flag) {
this.flag = flag;
}
@Override
public void run() {
if (flag == 1) {
synchronized (obj1) {
System.out.println("locking "+obj1); //占用obj1
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj2) {
System.out.println("使用順序 obj1 -> obj2");
}
}
} else if (flag == 2) {
synchronized (obj2) {
System.out.println("locking "+obj2); //占用obj2
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj1) {
System.out.println("使用順序 obj2 -> obj1");
}
}
}
}
}
public static void main(String[] args) throws InterruptedException {
MyTask myTask = new MyTask();
myTask.setFlag(1);
Thread thread1 = new Thread(myTask);
thread1.start();
//保證線程thread1優(yōu)先執(zhí)行
Thread.sleep(100);
myTask.setFlag(2);
Thread thread2 = new Thread(myTask);
thread2.start();
}
}
通過兩個線程去競爭資源從而達(dá)到死鎖目的
解決方案
MyTask myTask1 = new MyTask();
myTask1.setFlag(2);
Thread thread2 = new Thread(myTask1);
thread2.start();
理論上是可以解決死鎖励饵,但是并沒有成功再膳,WTF!想了好久原來是字符串常量的問題,需要通過new String()方式解決曲横,即
Object obj1 = new String("obj1");
Object obj2 = new String("obj2");