Java死锁问题解决方案及示例详解

2025-06-10 15:50

本文主要是介绍Java死锁问题解决方案及示例详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Java死锁问题解决方案及示例详解》死锁是指两个或多个线程因争夺资源而相互等待,导致所有线程都无法继续执行的一种状态,本文给大家详细介绍了Java死锁问题解决方案详解及实践样例,需要的朋友可以参考下...

1、简述

死锁(Deadlock) 是指两个或多个线程因争夺资源而相互等待,导致所有线程都无法继续执行的一种状态。

死锁的四个必要条件:

  • 互斥条件:某资源一次只能被一个线程占用。
  • 占有且等待:一个线程已持有资源并等待其他线程的资源。
  • 不可剥夺:资源不能被强行从线程中剥夺。
  • 循环等待:多个线程形成一种头尾相接的等待资源关系链。

只要这四个条件同时满足,就可能产生死锁。

2、死锁示例代码

下面是一个典型的死锁示例:

public class DeadlockExample {
    private static final Object LockA = new Object();
    private static final Object LockB = new Object();

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            synchronized (LockA) {
                System.out.println("Thread-1: locked A");

                try { Thread.sleep(100); } catch (InterruptedException e) {}

                synchronized (LockB) {
                    System.out.println("Threadjavascript-1: locked B");
                }
            }
        });

        Thread t2 = new Thread(() -> {
            synchronized (LockB) {
                System.out.println("Thread-2: locked B");

                try { Thread.sleep(100); } catch (InterruptedException e) {}

                synchronized (LockA) {
                    System.out.println("Thread-2: locked A");
                }
            }
        });

        t1.start();
        t2.start();
    }
}

运行这段程序可能会导致 Thread-1 等待 LockBThread-2 等待 LockA,从而产生死锁。

3、如何检测死锁?

3.1 使用 jstack

应用卡住时,使用如下命令查看线程堆栈:

jps      # 查找 Java 进程 ID
jstack <pid>

你会看到类似:

Found one Java-level deadlock:
"Thread-1": waiting to lock monitor 0x000..., which is held by "Thread-2"
...

3.2 使用 VisualVM 或 JConsole

这类工具可以图形化展示线程状态,识别死锁非常直观。

4、如何预防和解决死锁?

4.1 统一资源获取顺序(推荐)

确保多个线程获取多个锁时 按相同顺序加锁

public void safeMethod() {
    synchronized (LockA) {
        synchronized (LockB) {
            // 安全操作
        }
    }
}

4.2 使用 tryLock() 避免无限等待

使用 ReentrantLock 的 tryLock() 方法设置获取锁的超时时间。

import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;

public class TryLockExample {
    private final ReentrantLock lockA = new ReentrantLock();
    private final ReentrantLock lockB = new ReentrantLock();

    public void run() {
        Thread t1 = new Thread(() -> {
            try {
                if (lockA.tryLock(1, TimeUnit.SECONDS)) {
          javascript          System.out.println("Thread-1: locked A");
                    Thread.sleep(100);

                    if (lockB.tryLock(1, TimeUnit.SECONDS)) {
                        System.out.println("Thread-1: locked B");
                        lockB.ujsnlock();
                    }
                    lockA.unlock();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread t2 = new Thread(() -> {
            try {
                if (lockB.tryLock(1, TimeUnit.SECONDS)) {
                    System.out.println("Thread-2: locked B");
                    Thread.sleep(100);

                    if (lockA.tryLock(1ZNgkPO, TimeUnit.SECONDS)) {
                        System.out.println("Thread-2: locked A");
                        lockA.unlock();
                    }
                    lockB.unlock();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        t1.start();
        t2.start();
    }

    public static void main(String[] args) {
        new TryLockExample().run();
    }
}

4.3 使用 java.util.concurrent 包

避免使用低级的 synchronized,使用高php级并发工具如 ExecutorServiceSemaphoreLock 等更可控的工具。

4.4 死锁检测与恢复

一些大型系统中,可以通过定期扫描线程状态,自动检测死锁并重启部分线程或服务。例如通过自定义 ThreadMXBean 检测死锁。

最佳实践小结:

技术手段说明
加锁顺序统一所有线程按相同顺序获取资源
tryLock + timeout尝试加锁失败后避免长时间阻塞
lock 分解将大锁拆分成小锁减少竞争
并发工具替代 synchronized使用 ReentrantLock、Semaphore 等
死锁检测工具使用 jstack、VisualVM 等工具

5、结语

死锁是多线程编程中不可忽视的问题,但并不是无法避免。只要我们在设计时保持锁的有序性,并结合现代并发工具进行控制,绝大多数死锁问题都是可以预防的。

以上就是Java死锁问题解决方案及示例详解的详细内容,更多关于Java死锁问题解决的资料请关注China编程(www.chinasem.cn)其它相关文章!

这篇关于Java死锁问题解决方案及示例详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1154990

相关文章

Go语言中泄漏缓冲区的问题解决

《Go语言中泄漏缓冲区的问题解决》缓冲区是一种常见的数据结构,常被用于在不同的并发单元之间传递数据,然而,若缓冲区使用不当,就可能引发泄漏缓冲区问题,本文就来介绍一下问题的解决,感兴趣的可以了解一下... 目录引言泄漏缓冲区的基本概念代码示例:泄漏缓冲区的产生项目场景:Web 服务器中的请求缓冲场景描述代码

SpringBoot 中 CommandLineRunner的作用示例详解

《SpringBoot中CommandLineRunner的作用示例详解》SpringBoot提供的一种简单的实现方案就是添加一个model并实现CommandLineRunner接口,实现功能的... 目录1、CommandLineRunnerSpringBoot中CommandLineRunner的作用

详解Linux中常见环境变量的特点与设置

《详解Linux中常见环境变量的特点与设置》环境变量是操作系统和用户设置的一些动态键值对,为运行的程序提供配置信息,理解环境变量对于系统管理、软件开发都很重要,下面小编就为大家详细介绍一下吧... 目录前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变

解决JSONField、JsonProperty不生效的问题

《解决JSONField、JsonProperty不生效的问题》:本文主要介绍解决JSONField、JsonProperty不生效的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录jsONField、JsonProperty不生效javascript问题排查总结JSONField

html 滚动条滚动过快会留下边框线的解决方案

《html滚动条滚动过快会留下边框线的解决方案》:本文主要介绍了html滚动条滚动过快会留下边框线的解决方案,解决方法很简单,详细内容请阅读本文,希望能对你有所帮助... 滚动条滚动过快时,会留下边框线但其实大部分时候是这样的,没有多出边框线的滚动条滚动过快时留下边框线的问题通常与滚动条样式和滚动行

Java日期类详解(最新推荐)

《Java日期类详解(最新推荐)》早期版本主要使用java.util.Date、java.util.Calendar等类,Java8及以后引入了新的日期和时间API(JSR310),包含在ja... 目录旧的日期时间API新的日期时间 API(Java 8+)获取时间戳时间计算与其他日期时间类型的转换Dur

github打不开的问题分析及解决

《github打不开的问题分析及解决》:本文主要介绍github打不开的问题分析及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、找到github.com域名解析的ip地址二、找到github.global.ssl.fastly.net网址解析的ip地址三

Linux系统中的firewall-offline-cmd详解(收藏版)

《Linux系统中的firewall-offline-cmd详解(收藏版)》firewall-offline-cmd是firewalld的一个命令行工具,专门设计用于在没有运行firewalld服务的... 目录主要用途基本语法选项1. 状态管理2. 区域管理3. 服务管理4. 端口管理5. ICMP 阻断

Oracle修改端口号之后无法启动的解决方案

《Oracle修改端口号之后无法启动的解决方案》Oracle数据库更改端口后出现监听器无法启动的问题确实较为常见,但并非必然发生,这一问题通常源于​​配置错误或环境冲突​​,而非端口修改本身,以下是系... 目录一、问题根源分析​​​二、保姆级解决方案​​​​步骤1:修正监听器配置文件 (listener.

java对接海康摄像头的完整步骤记录

《java对接海康摄像头的完整步骤记录》在Java中调用海康威视摄像头通常需要使用海康威视提供的SDK,下面这篇文章主要给大家介绍了关于java对接海康摄像头的完整步骤,文中通过代码介绍的非常详细,需... 目录一、开发环境准备二、实现Java调用设备接口(一)加载动态链接库(二)结构体、接口重定义1.类型