1、什么是死锁?
死锁是指两个或者两个以上的进程在执行过程中,因争夺资源而造成的一种相互等待的现象,若无外力干涉,那它们就无法推进下去,如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很底,否则就会因为争夺有限资源而陷入死锁。
2、死锁模型图
3、死锁产生的四个条件:
互斥:共享资源X和Y只能被一个线程占用
占有且等待:线程T1已经获取共享资源X,在等待共享资源Y的时候,不释放共享资源X
不可抢占:其他线程不能强行抢占线程T1占有的资源
循环等待:线程T1等待线程T2占有的资源,线程T2等待线程T1占有的资源,这就是循环等待。
4、死锁手写编码 - 两个sync锁
class DeadLockResource implements Runnable{
private String lockA;
private String lockB;
public DeadLockResource(String lockA, String lockB) {
this.lockA = lockA;
this.lockB = lockB;
}
@Override
public void run() {
synchronized (lockA){
System.out.println(Thread.currentThread().getName() + " 拥有" + lockA + ",试图获取" + lockB);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB){
System.out.println(Thread.currentThread().getName() + " 拥有" + lockB);
}
}
}
}
/**
* 死锁是指两个或者两个以上的进程在执行过程中,
* 因争夺资源而造成的一种相互等待的现象,
* 若无外力干涉,那它们就无法推进下去,从而造成死锁现象。
* @Author: 小海
* @Description:
* @Date: Create in 15:53 2020-02-03
*/
public class DeadLockDemo {
public static void main(String[] args) {
String lockA = "lockA";
String lockB = "lockB";
new Thread(new DeadLockResource(lockA, lockB)).start();
new Thread(new DeadLockResource(lockB, lockA)).start();
}
}
5、死锁定位-DeadThread- jstack/jvisualvm/jconsole【JDK自带的命令行工具】
- jstack - 查看线程,主要用于线程栈分析,根据这个命令的输出可以定位某个进程的所有线程的当前运行状态、运行代码,以及是否死锁等等。
查看死锁线程的java进程id
Linux -> ps -ef | grep DeadThread
Window -> jps -l
> jstack + 进程号
- jvisualvm - 监控程序
- jconsole - Java性能分析器
5、预防死锁:
- 破坏占有且等待条件:保证一次申请所有的资源。
- 破坏不可抢占条件:synchronized无法做到,synchronized申请不到资源直接进入阻塞状态。 java.util.concurrent Lock可以解决此问题
- 破坏循环等待条件:需要对资源进行排序,然后按序申请资源
- 避免使用多个锁、长时间持有锁;
- 设计好多个锁的获取顺序
- 使用带超时的获取锁方法ReenTrantLock.tryLock
6、修复死锁
发生死锁无法在线解决,必须重启,修正程序本身的问题