死锁:指俩个或以上的线程循环等待其他线程占用的资源,但在未获取资源时又不放弃自己的资源。这种情况下如果没有外力作用,将永远等待下去。
比如:有A ,B两个资源,甲,乙两个线程。
甲——>A 甲占有A
乙——>B 乙占有B
这时候甲请求B,乙请求A,但是甲没请求到B的时候又不愿放弃A,乙没请求到A的时候不愿放弃B。两个进程都不能正常执行,这样两者就会无限的等待下去。
产生死锁的条件:
1:互斥条件。某个资源某刻只能由一个线程占用。
2:不可抢占条件。进程所获得资源在未使用完毕之前,资源申请者不能强行获取。
3:占用申请条件。
4:循环等待条件。
以上四个条件同时发生,即会产生死锁。
我们来看一下具体例子:
class Suo {
static Object so1 = new Object();
static Object so2 = new Object();
}
class DeadLocks implements Runnable {
public boolean flag;
public DeadLocks(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
// TODO Auto-generated method stub
if (flag) {
while (true) {
synchronized (Suo.so1) {//请求到so1并加锁
System.out.println("so1:"+ Thread.currentThread().getName());
synchronized (Suo.so2) {//请求so2,并加锁,由于so2被占用,故会一直等待
System.out.println("so2:"+ Thread.currentThread().getName());
}
}
}
} else {
while (true) {
synchronized (Suo.so2) {//请求到so2并加锁
System.out.println("so2:"+ Thread.currentThread().getName());
synchronized (Suo.so1) {//请求到so1并加锁,由于so1被占用,故会一直等待
System.out.println("so1:"+ Thread.currentThread().getName());
}
}
}
}
}
}
测试:
public class JstackDemo {
public static void main(String[] args) {
Thread t1 = new Thread(new DeadLocks(true));
Thread t2 = new Thread(new DeadLocks(false));
t1.start();
t2.start();
}
}
输出:
so1:Thread-0
so2:Thread-1
只打印两行,就不在打印下去了。
我们使用jstack打印下jvm堆栈信息
直接就可以看出:在34行和45发生死锁。
那么如何避免死锁呢。
只要打破上述四个条件之一就可解除死锁。
算法:银行家算法。
死锁的恢复:
1系统重启。
2撤销进程,剥夺资源。