[Java多线程-基础] 如何定位线程中的死锁问题?

2023-05-16

 🔒 死锁代码 

       下面提供的代码演示了死锁的情况。程序创建了两个线程,线程1和线程2,它们都试图以不同的顺序获取两个不同的资源,resource1和resource2。线程1首先获取resource1,然后等待resource2,而线程2首先获取resource2,然后等待resource1。

       这会创建一个死锁场景,其中两个线程都在等待另一个线程释放它们需要继续的资源。程序将不会终止,直到死锁得到解决

public static void main(String[] args) {

        //资源1
        Object resource1 = new Object();
        //资源2
        Object resource2 = new Object();

        // 创建线程1,占用资源1,等待资源2
        Thread thread1 = new Thread(() -> {
            synchronized (resource1) {
                System.out.println("Thread 1: 占用资源1");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (resource2) {
                    System.out.println("Thread 1: 占用资源2");
                }
            }
        });

        // 创建线程2,占用资源2,等待资源1
        Thread thread2 = new Thread(() -> {
            synchronized (resource2) {
                System.out.println("Thread 2: 占用资源2");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (resource1) {
                    System.out.println("Thread 2: 占用资源1");
                }
            }
        });

    // 启动线程1和线程2
        thread1.start();
        thread2.start();

    // 等待线程1和线程2执行完毕
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    // 此时线程1和线程2都已经执行完毕,程序结束

    }

✅ 执行结果

线程开始进入阻塞状态, 导致方法无法执行结束


📳 定位死锁

方案1:

1. 先用jps查看所有的java进程id

 2. jstack + 进程id定位死锁

从这里已经看出, 两个线程的状态都是BLOCKED,表示它们当前被阻塞等待某个对象的锁定。

 "Thread-0"正在等待锁定资源2,因为它已经占用了资源1,而"Thread-1"正在等待锁定资源1,因为它已经占用了资源2。这就是死锁发生的情况。

Found one Java-level deadlock的意思就是 发现一个Java级别的死锁

对应的线程分别为 Thread-1 和 Thread-0

 并且在下方还会提示你代码中死锁的位置 (死锁.java:38)

 方案2:

从jdk的安装路径中找到bin目录, 点击jconsole

 切换到线程, 点击检测死锁

通过以上两种方法, 我们就能很轻松的定位死锁的信息~

🔓 解决死锁的方案

在下面代码中,我们使用了可重入锁 ReentrantLock 来替代 synchronized 关键字进行线程同步。通过调用 lock() 方法获取锁,再使用 unlock() 方法释放锁。并且使用 try-catch-finally 语句块确保线程在任何情况下都会释放资源。

import java.util.concurrent.locks.ReentrantLock;

public class DeadlockSolution {
    public static void main(String[] args) {
        //资源1
        Object resource1 = new Object();
        //资源2
        Object resource2 = new Object();

        //创建可重入锁对象
        ReentrantLock lock1 = new ReentrantLock();
        ReentrantLock lock2 = new ReentrantLock();

        // 创建线程1,占用资源1,等待资源2
        Thread thread1 = new Thread(() -> {
            try {
                lock1.lock(); // 获取锁1
                System.out.println("Thread 1: 占用资源1");
                Thread.sleep(100);
                lock2.lock(); // 获取锁2
                System.out.println("Thread 1: 占用资源2");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock2.unlock(); // 释放锁2
                lock1.unlock(); // 释放锁1
            }
        });

        // 创建线程2,占用资源2,等待资源1
        Thread thread2 = new Thread(() -> {
            try {
                lock2.lock(); // 获取锁2
                System.out.println("Thread 2: 占用资源2");
                Thread.sleep(100);
                lock1.lock(); // 获取锁1
                System.out.println("Thread 2: 占用资源1");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock1.unlock(); // 释放锁1
                lock2.unlock(); // 释放锁2
            }
        });

        // 启动线程1和线程2
        thread1.start();
        thread2.start();

        // 等待线程1和线程2执行完毕
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 此时线程1和线程2都已经执行完毕,程序结束
    }
}

总的来说,ReentrantLock 提供了更高级的线程同步机制,并且具有更高的灵活性和性能,但是使用起来也更为复杂。而 synchronized 则是 Java 的基本语言特性,在简单情况下使用起来比较方便,但是在特定场景下可能会出现死锁等问题。

如果想详细了解ReentrantLock的使用可以参考文章 : 

[Java多线程-基础] 避免线程死锁问题(ReentrantLock的使用)_Max恒的博客-CSDN博客ReentrantLock 的设计初衷是为了提供一种比 synchronized 更加灵活和可控的锁机制。与 synchronized 相比,ReentrantLock 提供了更多的功能,如可重入性、公平锁和中断锁等,使得它在某些场景下更适用。具体来说,ReentrantLock 可以通过以下方式提供更好的控制和灵活性:1. 可重入性:允许线程多次获得同一个锁,避免死锁情况的发生。2. 公平锁:可以实现公平的锁分配机制,避免某些线程长期无法获取到锁而产生的饥饿问题。https://blog.csdn.net/qq_45481709/article/details/130451241?spm=1001.2014.3001.5501

扫描下方公众号二维码 领取多线程面试题 👇 👇 👇

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[Java多线程-基础] 如何定位线程中的死锁问题? 的相关文章

  • 线程池中线程抛了异常如何处理?

    文章目录 1 模拟线程池抛异常2 如何获取和处理异常方案一 xff1a 使用 try catch方案二 xff1a 使用Thread setDefaultUncaughtExceptionHandler方法捕获异常方案三 xff1a 重写a
  • ROS放弃指南2:ROS创建工作空间及五种设置环境变量的方法

    参考链接 xff1a 中国大学MOOC中的机器人操作系统入门 https www icourse163 org course ISCAS 1002580008 古月居博客 www guyuehome com 运行环境 xff1a Ubunt
  • 百科不全书之ROS函数解析

    1 ROS的回调函数 span class token comment 单线程 span ros span class token operator span span class token operator span span clas
  • VsCode 运行后终端没有结果

    最近入手了VsCode很多都还不太清楚 xff0c 稍微记录一下碰到的一点问题 也是第一次写博客 VsCode 运行后终端没有结果 一 运行后终端没有结果二 终端中文乱码问题 一 运行后终端没有结果 在网上试了好多好多解决方法都没有用 xf
  • STM32CubeMX(05) 移植陀螺仪MPU6050的DMP库读取三轴角度,加速度

    文章目录 前言一 MPU6050是什么 xff1f 二 STM32CubeMX配置2 1 IIC配置2 2 开启中断2 3 硬件连接2 4 软件编写 三 导入DMP库3 1 keil配置3 2 添加头文件路径3 3 添加头文件3 4 添加初
  • 基于STM32的智能GPS定位系统(云平台、小程序)

    如需源码或成品可以私我 背景及目标 前阵子 xff0c 准确的说是好几个月前买了一辆电瓶车 xff0c 当时呢因为车停得很随意 xff0c 所以想给小电驴装一个GPS xff0c 一方面是防盗 xff0c 另一方面是为了测速和绘制骑行轨迹
  • 蓝桥杯大赛

    第十一届蓝桥杯单片机比赛心得 前期的准备十月份省赛十一月份国赛错过结果发布 想要做一点事情 xff0c 传承 前期的准备 本次蓝桥杯大赛由于疫情原因延迟了将近7个月举行 xff0c 原先是3月份举行 xff0c 拖到了10月份 xff0c
  • 蓝桥杯模块练习之关闭外设

    蓝桥杯单片机比赛系列1初探关闭外设 关闭LED关闭继电器和蜂鸣器 关闭LED 本节将会介绍板子上的最简单最基础的部分 比赛一般上来需要关闭无关外设 xff0c 蓝桥杯的板子比较特殊 xff0c 51上电默认P0 O1 P2 P3都是高电平
  • 蓝桥杯模块练习之温度传感器DS18B20

    蓝桥杯单片机比赛系列4温度传感器DS18B20 温度传感器DS18B20原理相关电路onewire总线几个需要知道的暂存器和命令 代码解释修改代码自写代码 实现代码 温度传感器DS18B20原理 相关电路 DS18B20遵循onewire总
  • 被锡膏坑了一把

    锡膏 61 锡珠 43 助焊剂 把锡膏放大来看如下图 我是去年买的一罐锡膏 xff0c 138度的 xff0c 用了一两次 xff0c 然后就放在哪里没动它 xff0c 盖子也盖好了 xff0c 没有放冰箱 今年又拿出来用 xff0c 用钢
  • 蓝桥杯模块练习之AD/DA

    蓝桥杯单片机比赛系列6AD DA转换 AD DA原理相关电路pcf8591器件地址 代码解释修改代码AD自写代码ADDA AD DA原理 相关电路 通过pcf8591芯片实现ad转换 板子上ad采集主要采集滑动变阻器的电压值和与光敏电阻串联
  • 蓝桥杯模块练习之EEPROM

    蓝桥杯单片机比赛系列7EEPROM EEPROM原理相关电路AT24C02器件地址 EEPROM自写代码 EEPROM原理 相关电路 有了系列6的基础 xff0c 上手eeprom就简单多了 xff0c 板子上对应的器件是AT24C02 A
  • Openmv学习day1——色块识别

    find blobs函数 image find blobs thresholds roi 61 Auto x stride 61 2 y stride 61 1 invert 61 False area threshold 61 10 pi
  • 蓝桥杯嵌入式模块练习之扩展版MEME

    三轴传感器 PA4 7都不能作为其他用处 xff0c 三周传感器需要使用到这四个引脚资源 当然 xff0c 如果不用中断 xff0c 也可以只结PA4 5 xff0c PA6 7可接到温度传感器和温湿度传感器 这个外设的通信协议也是I2C跟
  • Github Pages 搭建网站

    个人站点 访问 https 用户名 gitub io 搭建步骤 1 创建个人站点 gt 新建仓库 xff08 仓库名必须是 用户名 github io xff09 2 在仓库下新建index heml文件即可 3 Github pages仅
  • 普通io口模拟串口通信

    之前公司在做项目的时候需要用到多串口 xff0c 板载串口资源不足 xff0c 就在网上找相关内容 xff0c 结合自己的理解做出虚拟串口 模拟串口需要用到两个普通io引脚 xff0c 一个定时器 软件串口的实现 IO模拟串口 波特率 xf
  • UART,SPI,IIC,RS232通信时序和规则

    一 UART 1 串口通信方式 2 串口通信步骤 注意 xff1a 串口协议规定 xff0c 闲置时必须是高电平 校验位 xff1a 是使用奇偶校验 停止位必须高电平 一个0和多个0区分是靠掐时间 异步通信 xff1a 时钟各不一样 二 I
  • kvaser pcie can 在ros中使用socketcan开发

    kvaser pcie can 在ros中使用socketcan开发 0 系统配置 Ubuntu 16 04 6 LTS Linux version 4 15 0 45 generic 1 官网下载地址 https www kvaser c
  • 算法训练 - 连接字符串 编程将两个字符串连接起来。例如country与side相连接成为countryside。   输入两行,每行一个字符串(只包含小写字母,长度不超过100);输出一行一个字符

    问题描述 编程将两个字符串连接起来 例如country与side相连接成为countryside 输入两行 xff0c 每行一个字符串 xff08 只包含小写字母 xff0c 长度不超过100 xff09 xff1b 输出一行一个字符串 例
  • 笔记 FreeRtos任务创建失败原因

    问题 使用NXP的S32芯片开发 xff0c 环境是S32DS 2018 xff0c 创建了三个任务 xff0c 最后发现只有一个任务在运行 找问题 S32DS自带了Freertos的分析调试工具 xff0c 打开后可以显示任务的状态 xf

随机推荐

  • 3.提升不同专业能力的差别?

    有段时间没写博客了 今天来谈谈最近工作的一些感悟 首先 我觉得工资和个人能力是成正相关的 这应该是是所有人都认同的吧 如果工资是一个函数的话 也可以说 工资 Y 是一个与个人能力 X 有关的一次函数Y aX b 方然我们不能忽略行业之间的差
  • 网络通讯学习(1)---TCP通讯

    TCP IP四层模型 UDP TCP协议 TCP xff08 The Transmission Control Protocol xff09 xff1a 传输控制协议 UDP TCP协议都属于传输层协议 xff0c 都位于IP协议以上 xf
  • 网络通讯学习(3)-----UDP通讯(仅了解)

    理论 UDP xff08 用户数据报协议 xff09 是一个无连接 xff0c 不可靠的数据传输 xff0c 其特点是简单 xff0c 快捷 相比与TCP xff0c UDP不需要建立连接 xff08 不需connect accept函数
  • WIFI模块不支持MQTT协议,可通过MCU实现

    1 话题原因 我们使用某款WIFI模块 xff0c 在物联网开发时 xff0c 平台端的开发者想要使用MQTT协议 xff0c 但是我们当前使用的模块不支持MQTT协议 xff08 好像ESP8266可以通过重新烧录固件的方式支持 xff0
  • (一) 路径规划算法---Astar与C++可视化在RVIZ的三维点云地图

    Astar与C 43 43 可视化在RVIZ的三维点云地图 文章目录 Astar与C 43 43 可视化在RVIZ的三维点云地图1 功能包介绍2 算法功能包的组成与介绍2 1文件系统组成2 2 头文件说明2 3 源文件说明 3 相关坐标系说
  • SpringSecurity整合OAuth2.0

    SpringSecurity整合OAuth2 一 概述与原理1 1 OAuth2 0 是什么 xff1f 1 2 OAuth2 0中角色解释1 3 OAuth2 0的4中授权模式1 3 1 授权码模式 xff08 重点 xff09 1 3
  • HAL_UART_IRQHandler(UART_HandleTypeDef *huart)里面的中断接收函数

    目录 前言1 UART Receive IT2 HAL UART Receive3 HAL UART Receive IT 前言 看了很长时间串口中断的HAL库 xff0c 最容易混淆的就是函数的名称 xff0c 主要集中在UART Rec
  • 位操作读写寄存器一个字节的多个位

    一 写寄存器多个位 方法一 span class token comment bitStart 目标字节的起始位 length 位长度 data 存放改变目标字节位的值 b 写入后的一个字节值 span u8 mask
  • STM32 电压采集上位机 C#

    工具箱中添加progressBar 添加一个事件函数 xff0c 用于串口接收数据 xff0c 并显示电压值 private void PortDataReceivedEvent object sender SerialDataReceiv
  • cmake使用教程(一)多目录下多个文件的构建

    1 采用 out of source 外部构建多个目录多个文件 这里的文件存储方式如下 xff1a 其中build是构建目录 xff0c 即构建的结果和中间产物都在该目录下 include是包含目录 src是子函数的目录或是依赖文件的目录
  • vue 实现遍历后端接口数据并展示在表格中

    用前端的vue遍历接口 首先就需要有后端的JSON数据 这里可以自己去写接口 可以伪造JSON数据 整理是伪造的JSON数据 34 userId 34 1 34 deptId 34 103 34 userName 34 34 admin 3
  • STM32的存储器映射中的指针操作

    例如 xff1a GPIOB的端口输出数据寄存器ODR的地址是0x4001 0C0C 并且ODR寄存器是32位的 那么我们可以用如下代码对寄存器进行操作 xff1a unsigned int 0x4001 0C0C 61 0xFFFFFFF
  • Mac 启动Redis报错 没有指定的conf文件

    报错如下 xff1a Warning no config file specified span class token punctuation span span class token keyword using span the de
  • java 优化双重for循环

    首先我们要有两个对象分别是 学生信息 和 学生住宿信息 span class token keyword class span span class token class name Student span span class toke
  • 微服务 - gateway网关配置

    server port 10010 网关端口 spring application name gateway 服务名称 cloud nacos server addr localhost 8848 nacos地址 gateway route
  • 如何在手机或平板上编写代码?

    下面给大家推荐一款免费的 在线协作式 基于浏览器的 IDE的在线编程网站 支持语言包括 Java C 43 43 C C JavaScript CSS PHP等50多种主流开发语言 地址 The collaborative browser
  • 羊了个羊, 低配版开源代码来啦~

    前几天朋友圈突然被一个小游戏 羊了个羊 刷屏了 xff0c 出于好奇我也打算小玩一把试试 xff0c 结果没想到上头了 游戏的玩法非常简单 xff0c 类似 消消乐 xff0c 从一堆方块中找到相同图案的 3 个方块并消除即可 但没想到 x
  • MySQL 使用索引和不使用索引的区别(附17W条数据SQL文件)

    MySQL 使用索引可以减少查询的时间 xff0c 而不使用索引的查询会更加耗时 xff0c 因为MySQL需要扫描整个表 此外 xff0c 使用索引可以提高查询的性能 xff0c 同时也可以提高查询的可读性和可维护性 换句话来说 使用索引
  • 如何使用AI来帮你写代码(Cursor使用教程)

    x1f4ac 产品介绍 cursor是一个新的Ide xff0c 它使用Ai来帮助您重构理解调试并使用Cursor编写代码我们的目标是使构建软件的过程更快 更愉快 我们从头开始构建了一个代码编辑器 xff0c 对我们的第一个功能进行了原型设
  • [Java多线程-基础] 如何定位线程中的死锁问题?

    x1f512 死锁代码 下面提供的代码演示了死锁的情况 程序创建了两个线程 xff0c 线程1和线程2 xff0c 它们都试图以不同的顺序获取两个不同的资源 xff0c resource1和resource2 线程1首先获取resource