it编程 > 编程语言 > Java

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

9人参与 2025-06-10 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("thread-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)) {
                    system.out.println("thread-1: locked a");
                    thread.sleep(100);

                    if (lockb.trylock(1, timeunit.seconds)) {
                        system.out.println("thread-1: locked b");
                        lockb.unlock();
                    }
                    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(1, 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,使用高级并发工具如 executorservicesemaphorelock 等更可控的工具。

4.4 死锁检测与恢复

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

最佳实践小结:

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

5、结语

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

以上就是java死锁问题解决方案及示例详解的详细内容,更多关于java死锁问题解决的资料请关注代码网其它相关文章!

(0)

您想发表意见!!点此发布评论

推荐阅读

SpringBoot 中 CommandLineRunner的作用示例详解

06-10

Java中的try-catch块和异常捕获方式

06-10

Java中的内存模型(JMM)和锁机制详解

06-10

java并发中的同步器使用方式

06-10

Java使用Spring AI的10个实用技巧分享

06-10

Java IO流必备之File、递归与字符集举例详解

06-10

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论