死锁的四个必要条件
1)互斥条件,即某个资源在一段时间内只能由一个线程占有,不能同时被两个或两个以上的线程占有
2)不可抢占条件,线程所获得的资源在未使用完毕之前,资源申请者不能强行地从资源占有者手中夺取资源,而只能由该资源的占有者线程自行释放
3)占有且申请条件,线程至少已经占有一个资源,但又申请新的资源;由于该资源已被另外线程占有,此时该线程阻塞;但是,它在等待新资源之时,仍继续占用已占有的资源。
4)循环等待条件,存在一个线程等待序列{P1,P2,...,Pn},其中P1等待P2所占有的某一资源,P2等待P3所占有的某一源,......,而Pn等待P1所占有的的某一资源,形成一个线程循环等待环
解决死锁的办法:加锁顺序,死锁检测
下面通过代码实例来讲解一下如何去写一个死锁代码&如何去解决死锁问题
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优先执行
Thread.sleep(100);
myTask.setFlag(2);
Thread thread2 = new Thread(myTask);
thread2.start();
}
}
通过两个线程去竞争资源从而达到死锁目的
解决方案
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");