一、死锁产生的原因
启动两个线程 监听两个对象, obj1 和 obj2 ,线程1 启动的时候先获得obj1 锁,暂停1s,再去获得obj2的锁,线程2启动的时候先获得obj2锁,在获取obj1的锁
当线程2获取obj2锁再去获得obj1对象的时候,发现obj1被线程1所占用此时就等到, 线程 1 1秒后获得,obj2,被线程2 占用,由于互相持有对方的锁,就会陷入无限的等待。这就产生死锁。回到整个程序代码无法执行下去,占用大量的内存空间,甚至导致系统崩溃。
private final Object obj1 = new Object();
private final Object obj2 = new Object();
private void test1() {
new Thread(){
@Override
public void run() {
synchronized (obj1){
try {
System.out.println("ydl---Thread1 obj1");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj2){
System.out.println("ydl---Thread1 obj2");
}
}
}
}.start();
new Thread(){
@Override
public void run() {
synchronized (obj2){
System.out.println("ydl---Thread2 obj2");
synchronized (obj1){
System.out.println("ydl---Thread2 obj1");
}
}
}
}.start();
}
//打印结果:
ydl---Thread1 obj1
ydl---Thread2 obj2
二、死锁产生的条件
互斥条件 : 一个资源每次只能让一个线城使用
请求和保持条件:一个线程请求资源阻塞时,不会释放资源
不剥夺条件:一个线程在执行资源未完成前,不能被剥夺
循环等待条件: 线程之间形成头尾衔接的循环等待条件。
三、怎么去定位死锁
jstack 获取线程栈,定位相互之间的依赖关系,进而就可以找到 死锁。
1.通过jps 和 任务管理器工具确定 进程ID
2.Jstack 获取线程栈 jstack your-pid
3.查看日志
四、解决死锁
1.最简单的就是 重新启动。但是 这种代价很大,之前的计算工作都会付之东流,
2.撤销进程,剥夺资源,终止参与死锁的进程,解除死锁。
3.进程回退:让进程回退到没有死锁的前某一点处,从这个点开始执行。