【死锁分享】Java面试官: 请说一个死锁的案例?

简介: 简单案例分享死锁,入门学习!
【辰兮要努力】:hello你好我是辰兮,很高兴你能来阅读,昵称是希望自己能不断精进,向着优秀程序员前行!

博客来源于项目以及编程中遇到的问题总结,偶尔会有读书分享,我会陆续更新Java前端、后台、数据库、项目案例等相关知识点总结,感谢你的阅读和关注,希望我的博客能帮助到更多的人,分享获取新知,大家一起进步!

吾等采石之人,应怀大教堂之心,愿大家奔赴在各自的热爱里…

一、初识死锁

面试官:谈一下你对死锁的理解?
请添加图片描述

死锁就是两个或多个线程(或进程)被无限期地阻塞,相互等待对方手中资源的一种状态

一旦发生了死锁,根据发生死锁的线程的职责不同,就可能会造成 子系统崩溃、性能降低 甚至 整个系统崩溃 等各种不良后果。而且死锁往往发生在高并发、高负载的情况下,因为可能会直接影响到很多用户,造成一系列的问题


Java 死锁产生的四个必要条件:

1、互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用
2、不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
3、请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
4、循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路

打破死锁即打破如上四个中的一个满足条件即可


二、案例分析

面试官:请简单的写出一个具体的死锁案例!

请添加图片描述

如下两个对象在调度a资源的时候需要调度b资源,同时调度b资源的时候需要调度a资源,资源得不到释放,产生死锁

/**
 * 2021-9-11 15:52:43
 * 辰兮要努力
 */
public class TestDeadLock {
    /*
     * 所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进
     */

    public static void main(String[] args) {
       //创建两个资源 a资源和b资源互相调度
        final Object a = new Object();
        final Object b = new Object();


       //线程A,按照先锁a再获得锁b的的顺序获得锁
        new Thread() {
            @Override
            public void run(){
                    synchronized (a) {
                        System.out.println(Thread.currentThread().getName()+ "线程 已获取 a资源");

                        try {
                            //线程睡两秒
                            Thread.sleep(2000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()+ "线程 想获取 b资源");
                        synchronized (b) {
                            System.out.println(Thread.currentThread().getName() + "win");
                        }
                    }
            }
        }.start();

        //线程B先获取锁b再锁a的顺序获得锁
        new Thread() {
            @Override
            public void run(){
                synchronized (b) {
                    System.out.println(Thread.currentThread().getName()+ "线程 已获取 b资源");
                    //线程睡两秒
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+ "线程 想获取 a资源");
                    synchronized (a) {
                        System.out.println(Thread.currentThread().getName() + "win");
                    }
                }
            }
        }.start();
        
    }
}

执行效果如下
在这里插入图片描述

死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去


三、排查解决

面试官:你如何排查项目中的死锁问题呢?
请添加图片描述

jps(Java Virtual Machine Process Status Tool)

jps是java提供的一个显示当前所有java进程pid的命令,适合在linux/unix平台上简单察看当前java进程的一些简单情况

在这里插入图片描述
输入的效果

C:\Users\lenovo>jps
10608 TestDeadLock
10848 Launcher
6640
18408 Jps
18460 KotlinCompileDaemon

jstack是java虚拟机自带的一种堆栈跟踪工具。

jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因

C:\Users\lenovo>jstack 10608

输入的效果
在这里插入图片描述

Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x0000000003488e08 (object 0x000000076be21938, a java.lang.Object),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x000000000348b698 (object 0x000000076be21948, a java.lang.Object),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
        at com.chenxi.TestDeadLock$2.run(TestDeadLock.java:53)
        - waiting to lock <0x000000076be21938> (a java.lang.Object)
        - locked <0x000000076be21948> (a java.lang.Object)
"Thread-0":
        at com.chenxi.TestDeadLock$1.run(TestDeadLock.java:33)
        - waiting to lock <0x000000076be21948> (a java.lang.Object)
        - locked <0x000000076be21938> (a java.lang.Object)

Found 1 deadlock.

如上的日志
"Thread-1":等待的去锁 <0x000000076be21938>
同时已经锁住了 <0x000000076be21948>

"Thread-0":等待的去锁 <0x000000076be21948>
同时已经锁住了<0x000000076be21938>

Found 1 deadlock.

同时日志里面有产生死锁的类和具体的行数

如上的方法我们可以准确的定位到死锁具体产生的位置,具体的业务场景就根据具体的情况分析解决


非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤️ 分享👥 留言💬thanks!!!

愿你们奔赴在自己的热爱里!

目录
相关文章
|
6天前
|
负载均衡 NoSQL 算法
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
这篇文章是关于Java面试中Redis相关问题的笔记,包括Redis事务实现、集群方案、主从复制原理、CAP和BASE理论以及负载均衡算法和类型。
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
|
6天前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
6天前
|
存储 监控 安全
一天十道Java面试题----第三天(对线程安全的理解------>线程池中阻塞队列的作用)
这篇文章是Java面试第三天的笔记,讨论了线程安全、Thread与Runnable的区别、守护线程、ThreadLocal原理及内存泄漏问题、并发并行串行的概念、并发三大特性、线程池的使用原因和解释、线程池处理流程,以及线程池中阻塞队列的作用和设计考虑。
|
1天前
|
人工智能 Java 定位技术
人工智能ChatGPT 体验案例:使用ChatGPT实现java扫雷小游戏
这篇文章通过一个使用ChatGPT实现的Java扫雷小游戏案例,展示了ChatGPT在编程领域的应用能力。文章中包含了扫雷游戏的Java代码实现,代码中初始化了雷区地图,随机放置雷,计算每个格子周围雷的数量,并提供了一个简单的文本界面与用户交互进行游戏。游戏通过控制台输入接受玩家的指令,并给出相应的反馈。
人工智能ChatGPT 体验案例:使用ChatGPT实现java扫雷小游戏
|
6天前
|
存储 NoSQL Java
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
这篇文章是关于Java面试中的分布式架构问题的笔记,包括分布式架构下的Session共享方案、RPC和RMI的理解、分布式ID生成方案、分布式锁解决方案以及分布式事务解决方案。
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
|
6天前
|
存储 安全 Java
一天十道Java面试题----第二天(HashMap和hashTable的区别--------》sleep、wait、join)
这篇文章是关于Java面试的第二天笔记,涵盖了HashMap与HashTable的区别、ConcurrentHashMap的实现原理、IOC容器的实现方法、字节码的概念和作用、Java类加载器的类型、双亲委派模型、Java异常体系、GC如何判断对象可回收、线程的生命周期及状态,以及sleep、wait、join、yield的区别等十道面试题。
一天十道Java面试题----第二天(HashMap和hashTable的区别--------》sleep、wait、join)
|
1天前
|
设计模式 Java
常用设计模式介绍~~~ Java实现 【概念+案例+代码】
文章提供了一份常用设计模式的全面介绍,包括创建型模式、结构型模式和行为型模式。每种设计模式都有详细的概念讲解、案例说明、代码实例以及运行截图。作者通过这些模式的介绍,旨在帮助读者更好地理解源码、编写更优雅的代码,并进行系统重构。同时,文章还提供了GitHub上的源码地址,方便读者直接访问和学习。
常用设计模式介绍~~~ Java实现 【概念+案例+代码】
|
4天前
|
存储 SQL 关系型数据库
深入MySQL锁机制:原理、死锁解决及Java防范技巧
深入MySQL锁机制:原理、死锁解决及Java防范技巧
|
6天前
|
SQL Java 数据库连接
一天五道Java面试题----第六天(1)
这篇文章是关于Java面试中常见的五个问题,包括MyBatis和Hibernate的对比、MyBatis中#{}和${}的区别、MyBatis插件的运行原理及开发流程、索引的基本原理以及MySQL聚簇索引和非聚簇索引的区别。
|
6天前
|
缓存 NoSQL Redis
一天五道Java面试题----第九天(简述MySQL中索引类型对数据库的性能的影响--------->缓存雪崩、缓存穿透、缓存击穿)
这篇文章是关于Java面试中可能会遇到的五个问题,包括MySQL索引类型及其对数据库性能的影响、Redis的RDB和AOF持久化机制、Redis的过期键删除策略、Redis的单线程模型为何高效,以及缓存雪崩、缓存穿透和缓存击穿的概念及其解决方案。