Java模拟排查线程死锁问题

本文通过一个简单的Java示例程序模拟了死锁现象,并介绍了如何使用top、jstack等命令来排查死锁问题。此外,还提供了几个常用的JVM命令帮助理解程序运行时的状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、模拟死锁

public class App 
{
    public static void main( String[] args )
    {
        Object object1 = new Object();
        Object object2 = new Object();

        System.out.println("main thread start");
        Thread thread1 = new Thread(new Task1(object1,object2));
        thread1.start();


        Thread thread2 = new Thread(new Task2(object1,object2));
        thread2.start();

        System.out.println("main thread end");

    }

}

class Task1 implements Runnable {

    private Object curObj1;
    private Object curObj2;

    public Task1 (Object obj1,Object obj2) {
        this.curObj1 = obj1;
        this.curObj2 = obj2;
    }

    public void run() {
        System.out.println(Thread.currentThread().getName() + " start");

        synchronized (curObj1) {
            System.out.println(Thread.currentThread().getName() + " get lock on Object1");

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized (curObj2) {
                System.out.println(Thread.currentThread().getName() + " get lock on Object2");
            }

        }

        System.out.println(Thread.currentThread().getName() + " end");
    }
}

class Task2 implements Runnable {

    private Object curObj1;
    private Object curObj2;

    public Task2 (Object obj1,Object obj2) {
        this.curObj1 = obj1;
        this.curObj2 = obj2;
    }

    public void run() {
        System.out.println(Thread.currentThread().getName() + " start");

        synchronized (curObj2) {
            System.out.println(Thread.currentThread().getName() + " get lock on Object2");

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized (curObj1) {
                System.out.println(Thread.currentThread().getName() + " get lock on Object1");
            }
        }



        System.out.println(Thread.currentThread().getName() + " end");
    }
}

1、两个线程分别互相等待对方释放对象锁

2、打包成jar(注意在POM中加入maven-jar-plugin插件,否则打包出来的jar在执行时会报错找不到manifest)

3、java  -jar   jarname  执行

二、排查死锁

1、top查看CPU和内存使用率

2、找到资源占用率比较高的进程PID

3、分析PID

4、显示PID下面的线程

     top -H  -p  pid

5、查看具体某个线程

     jstack -l  pid | grep  xxx -A  20

6、jvm常用命令

(1)jps 查看启动的JVM进程

(2)jinfo  pid 查看某个JVM进程ClassPath、VM参数设置等

(3)jstat 查看某个JVM进程运行状态:GC情况等

(4)jstack 查看某个JVM进程下所有线程的运行状态

(5)jmap 查看某个JVM进程下堆中存储的对象


查看结果:




### Java排查死锁的命令 `jstack` 示例 #### 使用 `jstack` 排查死锁 当怀疑 Java 应用程序中存在死锁时,可以通过以下方式使用 `jstack` 工具生成线程转储并分析死锁情况: 1. **找到 Java 进程 ID** 首先需要确定目标 Java 应用程序的进程 ID(PID)。可以使用以下两种方法之一: - 使用 `jps` 命令列出所有 Java 进程及其对应的 PID[^1]。 ```bash jps -l ``` - 或者通过系统命令查找 Java 进程: ```bash ps -ef | grep java ``` 2. **生成线程转储** 使用 `jstack` 命令针对指定的 Java 进程生成线程转储文件。以下是基本语法: ```bash jstack [选项] <pid> ``` 其中 `[选项]` 可以为 `-l` 表示提供更详细的锁定信息。 示例: ```bash jstack -l 12345 > thread_dump.txt ``` 上述命令将生成线程转储并将输出保存到 `thread_dump.txt` 文件中[^1]。 3. **分析线程转储** 在生成的线程转储文件中,如果存在死锁,则会在文件末尾部分显示类似于以下的内容: ``` Found one Java-level deadlock: ============================= "Thread-1": waiting to lock monitor 0x00007f8c5400b800 (object 0x000000076a9eacf0, a java.lang.Object), which is held by "Thread-2" "Thread-2": waiting to lock monitor 0x00007f8c5400c800 (object 0x000000076a9ebcf0, a java.lang.Object), which is held by "Thread-1" Java stack information for the threads listed above: =================================================== "Thread-1": at com.example.DeadLockTest.lambda$main$0(DeadLockTest.java:10) - waiting to lock <0x000000076a9eacf0> (a java.lang.Object) - locked <0x000000076a9ebcf0> (a java.lang.Object) "Thread-2": at com.example.DeadLockTest.lambda$main$1(DeadLockTest.java:18) - waiting to lock <0x000000076a9ebcf0> (a java.lang.Object) - locked <0x000000076a9eacf0> (a java.lang.Object) Found 1 deadlock. ``` 上述输出表明两个线程之间发生了死锁,分别持有对方所需的锁资源[^3]。 --- #### 示例代码:模拟死锁场景 为了更好地理解如何使用 `jstack` 排查死锁,可以参考以下简单的死锁模拟代码: ```java public class DeadLockTest { private static final Object LOCK_1 = new Object(); private static final Object LOCK_2 = new Object(); public static void main(String[] args) { new Thread(() -> { synchronized (LOCK_1) { try { System.out.println("Thread 1 acquired LOCK_1"); Thread.sleep(100); } catch (InterruptedException e) {} synchronized (LOCK_2) { System.out.println("Thread 1 acquired LOCK_2"); } } }, "Thread-1").start(); new Thread(() -> { synchronized (LOCK_2) { try { System.out.println("Thread 2 acquired LOCK_2"); Thread.sleep(100); } catch (InterruptedException e) {} synchronized (LOCK_1) { System.out.println("Thread 2 acquired LOCK_1"); } } }, "Thread-2").start(); } } ``` 运行此代码后,应用程序可能会进入死锁状态。此时可使用 `jstack` 分析其原因。 --- #### 使用 `ThreadMXBean` 动态检测死锁 除了手动分析线程转储外,还可以利用 `ThreadMXBean` 提供的功能动态检测死锁。以下是一个简单示例: ```java import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; public class DeadlockDetector { public static void main(String[] args) { ThreadMXBean bean = ManagementFactory.getThreadMXBean(); long[] deadlockedThreads = bean.findDeadlockedThreads(); if (deadlockedThreads != null && deadlockedThreads.length > 0) { System.out.println("Detected deadlock between following threads:"); for (long id : deadlockedThreads) { ThreadInfo info = bean.getThreadInfo(id); System.out.printf("- %s (%d)%n", info.getThreadName(), id); } } else { System.out.println("No deadlocks detected."); } } } ``` 上述代码能够实时检测 JVM 中是否存在死锁,并返回涉及的线程名称和 ID[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值