Java多线程之死锁详解

时间:2021-12-18 05:39:16

1、死锁

出现场景:当线程A拥有了A对象的锁,想要去获取B对象的锁;线程B拥有了B对象的锁,想要拥有A对象的锁,两个线程在获取锁的时候,都不会释放已经持有的锁,于是,就造成了死锁。

示例代码:

@Slf4j
public class ThreadTest {
  private static Object objectA = new Object();
  private static Object objectB = new Object();
  public static void main(String[] args) throws InterruptedException {
      Thread t2 = new Thread(()->{
          synchronized (objectA){
              log.debug("线程t2获取到了objectA");
              synchronized (objectB){
                  log.debug("线程t2获取到了objectB");
              }
          }
      },"t2");
      Thread t1 = new Thread(()->{
          synchronized (objectB){
              log.debug("线程t1获取到了objectB");
              synchronized (objectA){
                  log.debug("线程t1获取到了objectA");
              }
          }
      },"t1");
      t2.start();
      t1.start();
  }
}

如何检测死锁:

两种方法

(1)找到本机jconsole程序,直接在windows系统搜索就可以,打开是这个样子。

Java多线程之死锁详解

然后在本地进程里面选择你的进程,其实就是你的项目名称。然后点击连接,在点击不安全连接。

​​​​​​​Java多线程之死锁详解

进去之后点击线程

Java多线程之死锁详解

再点击检测死锁

Java多线程之死锁详解

最后就能看到死锁的线程了

Java多线程之死锁详解

(2)首先是在idea的控制台,打开Terminal,输入【jps】命令查看所有的进程id,找到你自己的java类名称对应的id。

然后输入【jstack + 进程号】 就可以查询到该进程的所有线程信息。在输出信息的最下面,就可以看到如下图所示的线程死锁信息。

Java多线程之死锁详解

 

2、死锁经典问题――哲学家就餐问题

经典场景:有四位哲学及在一正方形的桌子上面吃饭,桌子的每个角有一根筷子,一共四根,那么,当每个哲学家都拿起自己左边的筷子之后,再去拿自己右边的筷子的时候,就会发现自己右边没有筷子,这时哲学就就会等右边的哲学家放下筷子,但是每个哲学家都是这个想法,那么都不会放下筷子,并且都拿不到右边的筷子,因此就造成了死锁。

代码实现例子:

@Slf4j
public class Thread1 {
  public static void main(String[] args) throws InterruptedException {
      //筷子对象
      Chopsticks c1 = new Chopsticks("c1");
      Chopsticks c2 = new Chopsticks("c2");
      Chopsticks c3 = new Chopsticks("c3");
      Chopsticks c4 = new Chopsticks("c4");
      new Philosopher("李云龙",c1,c2).start();
      new Philosopher("赵刚",c2,c3).start();
      new Philosopher("魏和尚",c3,c4).start();
      new Philosopher("张大彪",c4,c1).start();
  }
}
//筷子
class  Chopsticks{
  private String name;

  public Chopsticks(String name) {
      this.name = name;
  }
}
//哲学家
@Slf4j
class Philosopher extends Thread{
  //名字
  private String name;
  //筷子
  private Chopsticks left;
  private Chopsticks right;

  public Philosopher(String name, Chopsticks left, Chopsticks right) {
      super(name);
      this.left = left;
      this.right = right;
  }

  @Override
  public void run() {
      while(true){
          synchronized (right){
              synchronized (left){
                  eat(name);
              }
          }
      }
  }
  private void eat(String name){
      log.debug(name + "正在吃饭");
  }
}

测试结果:可以实现吃饭操作,但是会出现场景中描述的问题,出现线程死锁。

Java多线程之死锁详解

 

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注服务器之家的更多内容!

原文链接:https://blog.csdn.net/qq_42251944/article/details/120879781