简介:所谓死锁就是描述两个或多个线程因竞争资源出现等待彼此造成永久阻塞的情况,若无外力作用,形成一种“僵局”。
java 死锁产生的四个必要条件:
1、互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用。
2、请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放。
3、不剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。
4、环路等待条件:在发生死锁时,必然存在一个进程–资源的环形链
当上述四个条件都成立的时候,便形成死锁。当然,死锁的情况下如果打破上述任何一个条件,便可让死锁消失。 看看下面一个例子
实例1:
public class DeadLockTest {
public static Object lock1 = new Object();
public static Object lock2 = new Object();
public static void main(String[] args) {
LockThreadDemo1 lockThreadDemo1 = new LockThreadDemo1();
LockThreadDemo2 lockThreadDemo2 = new LockThreadDemo2();
lockThreadDemo1.start();
lockThreadDemo2.start();
}
private static class LockThreadDemo1 extends Thread{
public void run(){
synchronized (lock1) {
System.out.println("Thread 1:Holding lock 1...");
try{Thread.sleep(10);}
catch(InterruptedException e){}
System.out.println("Thread 1:Waiting for lock 2...");
synchronized (lock2) {
System.out.println("Thread 1:Holding lock 1 & 2...");
}
}
}
}
private static class LockThreadDemo2 extends Thread{
public void run(){
synchronized (lock2) {
System.out.println("Thread 2:Holding lock 2...");
try{Thread.sleep(10);}
catch(InterruptedException e){}
System.out.println("Thread 2:Waiting for lock 1...");
synchronized (lock1) {
System.out.println("Thread 2:Holding lock 1 & 2...");
}
}
}
}
}
当您编译并执行上述程序时,会出现死锁情况,以下是程序生成的输出 :
上述程序将永久挂起,因为两个线程都不能继续进行,等待彼此释放锁定,只能强制退出程序。
实例2:
下面我们修改锁的顺序并运行相同的程序,看看这两个线程是否仍然相互等待。
public class DeadLockTest {
public static Object lock1 = new Object();
public static Object lock2 = new Object();
public static void main(String[] args) {
LockThreadDemo1 lockThreadDemo1 = new LockThreadDemo1();
LockThreadDemo2 lockThreadDemo2 = new LockThreadDemo2();
lockThreadDemo1.start();
lockThreadDemo2.start();
}
private static class LockThreadDemo1 extends Thread{
public void run(){
synchronized (lock1) {
System.out.println("Thread 1:Holding lock 1...");
try{Thread.sleep(10);}
catch(InterruptedException e){}
System.out.println("Thread 1:Waiting for lock 2...");
synchronized (lock2) {
System.out.println("Thread 1:Holding lock 1 & 2...");
}
}
}
}
private static class LockThreadDemo2 extends Thread{
public void run(){
synchronized (lock1) {
System.out.println("Thread 2:Holding lock 1...");
try{Thread.sleep(10);}
catch(InterruptedException e){}
System.out.println("Thread 2:Waiting for lock 2...");
synchronized (lock1) {
System.out.println("Thread 2:Holding lock 1 & 2...");
}
}
}
}
}
所以只是改变锁的顺序防止程序进入死锁情况并完成以下结果
总结:
上面的例子只是为了更容易理解这个解决死锁的概念,然而,这是一个复杂的概念,深入理解才能实际应用。在这里总结下避免死锁的几种方式:
1、让程序每次至多只能获得一个锁。当然,在多线程环境下,这种情况通常并不现实。
2、设计时考虑清楚锁的顺序,尽量减少嵌在的加锁交互数量。
3、既然死锁的产生是两个线程无限等待对方持有的锁,那么只要等待时间有个上限不就好了。当然synchronized不具备这个功能,但是我们可以使用Lock类中的tryLock方法去尝试获取锁,这个方法可以指定一个超时时限,在等待超过该时限之后便会返回一个失败信息(后续介绍lock接口)