死锁的概念
死锁是指在多线程或多进程中,两个或两个以上的线程或进程在执行过程中,因抢夺资源而造成的一种相互等待的现象。简单来说,就是两个或两个以上的线程或进程都在等待对方释放资源,从而导致所有线程或进程都无法继续执行的情况。
死锁的示例
有两个线程A,B,线程A占用了锁A,线程B占用了锁B,在这种情况下线程A又想获取锁B,线程B也想获取锁A,自己不释放锁,却又都在等待对象释放锁资源,相互僵持,就会造成死锁。
死锁代码演示
// 模拟死锁
public class Demo0 {public static void main(String[] args) {String lock1 = "lock1";String lock2 = "lock2";new Thread(new DeadLock(lock1,lock2),"线程1").start();new Thread(new DeadLock(lock2,lock1),"线程2").start();}}class DeadLock implements Runnable{private String lock1;private String lock2;public DeadLock(String lock1,String lock2) {this.lock1 = lock1;this.lock2 = lock2;}@Overridepublic void run() {synchronized (lock1) {System.out.println(Thread.currentThread().getName()+"获取"+lock1);try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (lock2) {System.out.println(Thread.currentThread().getName()+"获取"+lock2);}}}
}
死锁的必要条件(四点)
- 互斥:一个资源每次只能被一个进程或线程使用
- 请求与保持:一个进程或线程请求资源而阻塞时,对已经获得的资源保持不放。
- 不可抢占:进程或线程以获得的资源,在未使用完之前,不能强行剥夺。
- 循环等待:若干进程或线程之间形成一种头尾相接的循环等待资源关系。
死锁的排查方法
- 查看日志
- 打印堆栈信息
- 使用jdk提供的可视化工具 jconsole
演示打印堆栈信息
- 第一步:使用 jps -l 查看所有正在运行的线程信息,获取线程id
- 第二步:使用 jstack 线程id 定位线程死锁的详细信息
演示可视化工具 jconsole
首先找到该工具 ,其位于jdk的bin目录下
死锁的解决办法
预防:死锁的产生是有四个必要条件的,那么只要破环其中一个条件,就不会出现死锁。但是必要条件中互斥条件又是锁的特性。破环其他三个条件之一就行。
避免:避免死锁与预防死锁的区别在于:预防死锁是设法至少破坏产生死锁的必要条件之一,严格地防止死锁的出现。而避免死锁,则是在进程请求分配资源时,采用某种算法(银行家算法)来预防可能发生的死锁,从而拒绝可能引起死锁的某个资源请求。