Java多线程之死锁详解

 更新时间:2021年10月26日 10:58:39   作者:不关阿强的事  
这篇文章主要介绍了Java多线程的死锁,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

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系统搜索就可以,打开是这个样子。

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

 ​​​​​​​

 进去之后点击线程

 再点击检测死锁

 

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

 

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

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

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使用正则表达式判断独立字符的存在(代码示例)

    Java使用正则表达式判断独立字符的存在(代码示例)

    通过使用正则表达式,我们可以更加灵活地判断字符串中是否包含特定的字符,并且可以控制匹配的条件,如独立的字符,这为我们处理字符串提供了更多的选择和功能,这篇文章主要介绍了Java使用正则表达式判断独立字符的存在,需要的朋友可以参考下
    2023-10-10
  • SpringBoot整合Quartz实现定时任务详解

    SpringBoot整合Quartz实现定时任务详解

    这篇文章主要介绍了Java 任务调度框架 Quartz,Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,完全由Java开发,可以用来执行定时任务,类似于java.util.Timer。,下面我们来学习一下关于 Quartz更多的详细内容,需要的朋友可以参考一下
    2022-08-08
  • Spring Boot数据库链接池配置方法

    Spring Boot数据库链接池配置方法

    这篇文章主要介绍了Spring Boot数据库链接池配置方法,需要的朋友可以参考下
    2017-04-04
  • 利用HttpUrlConnection 上传 接收文件的实现方法

    利用HttpUrlConnection 上传 接收文件的实现方法

    下面小编就为大家带来一篇利用HttpUrlConnection 上传 接收文件的实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-11-11
  • Springboot打印接口的三种方式分享

    Springboot打印接口的三种方式分享

    这篇文章主要为大家详细介绍了Springboot打印接口的三种方式:aop切面的方式、过滤器的方式和拦截器的方式,感兴趣的可以跟随小编一起学习一下
    2022-08-08
  • FastJSON的0day漏洞的解决

    FastJSON的0day漏洞的解决

    本文主要介绍了FastJSON的0day漏洞的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • Java秒杀系统:web层详解

    Java秒杀系统:web层详解

    本文主要介绍了如何设计一个秒杀系统的web层相关知识。具有很好的参考价值。下面跟着小编一起来看下吧,希望能够给你带来帮助
    2021-10-10
  • java 中设计模式之单例

    java 中设计模式之单例

    这篇文章主要介绍了java 中设计模式之单例的相关资料,这里说明恶汉模式与懒汉模式,需要的朋友可以参考下
    2017-08-08
  • 利用Java如何实现将二维数组转化为链式储存

    利用Java如何实现将二维数组转化为链式储存

    链式结构不要求逻辑上相邻的节点在物理位置上也相邻,节点间的逻辑关系是由附加的指针字段表示的,通常借助于程序设计中的指针结构来实现,这篇文章主要给大家介绍了关于利用Java如何实现将二维数组转化为链式储存的相关资料,需要的朋友可以参考下
    2021-12-12
  • 通过一个map替换字符串中指定的字符变量方法

    通过一个map替换字符串中指定的字符变量方法

    下面小编就为大家带来一篇通过一个map替换字符串中指定的字符变量方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-03-03

最新评论