Java实现线程dump分析案例

wen java案例 1

本文目录导读:

Java实现线程dump分析案例

  1. 生成线程Dump的多种方式
  2. 模拟问题场景
  3. 线程Dump分析工具类
  4. 实战分析示例
  5. 自定义ThreadDump监视工具
  6. 分析脚本示例
  7. 使用步骤

我将为您提供一个完整的Java线程Dump分析案例,包括示例代码、Dump生成方法和分析技巧。

生成线程Dump的多种方式

// 方法1:使用jstack命令
// jstack <pid> > thread_dump.txt
// 方法2:使用jcmd命令
// jcmd <pid> Thread.print > thread_dump.txt
// 方法3:代码中获取
public class ThreadDumpGenerator {
    public static void main(String[] args) {
        // 获取所有线程的堆栈信息
        for (Thread thread : Thread.getAllStackTraces().keySet()) {
            System.out.println("Thread: " + thread.getName());
            System.out.println("State: " + thread.getState());
            System.out.println("Daemon: " + thread.isDaemon());
            StackTraceElement[] stackTrace = thread.getStackTrace();
            for (StackTraceElement element : stackTrace) {
                System.out.println("\tat " + element);
            }
            System.out.println("--------------------------------");
        }
    }
}

模拟问题场景

创建一个模拟死锁和线程争用的示例:

public class ThreadDumpAnalysisExample {
    // 模拟死锁场景
    static class DeadlockSimulator {
        private final Object lock1 = new Object();
        private final Object lock2 = new Object();
        public void method1() {
            synchronized (lock1) {
                System.out.println("Thread A acquired lock1");
                try { Thread.sleep(100); } catch (InterruptedException e) {}
                synchronized (lock2) {
                    System.out.println("Thread A acquired lock2");
                }
            }
        }
        public void method2() {
            synchronized (lock2) {
                System.out.println("Thread B acquired lock2");
                try { Thread.sleep(100); } catch (InterruptedException e) {}
                synchronized (lock1) {
                    System.out.println("Thread B acquired lock1");
                }
            }
        }
    }
    // 模拟线程池阻塞
    static class ThreadPoolSimulator {
        public void simulateBlockedThreads() {
            for (int i = 0; i < 10; i++) {
                new Thread(() -> {
                    try {
                        System.out.println(Thread.currentThread().getName() + " is running");
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }, "Worker-" + i).start();
            }
        }
    }
    // 模拟CPU密集型任务
    static class CPUSimulator {
        public void simulateCPUIntensive() {
            new Thread(() -> {
                long sum = 0;
                while (true) {
                    sum += 1;
                    if (sum % 1000000000 == 0) {
                        System.out.println("CPU intensive task: " + sum);
                    }
                }
            }, "CPU-Intensive-Thread").start();
        }
    }
    public static void main(String[] args) throws InterruptedException {
        // 启动所有模拟器
        DeadlockSimulator deadlock = new DeadlockSimulator();
        ThreadPoolSimulator pool = new ThreadPoolSimulator();
        CPUSimulator cpu = new CPUSimulator();
        // 创建死锁线程
        Thread ta = new Thread(deadlock::method1, "Thread-A");
        Thread tb = new Thread(deadlock::method2, "Thread-B");
        ta.start();
        tb.start();
        // 启动线程池模拟
        pool.simulateBlockedThreads();
        // 启动CPU密集型任务
        cpu.simulateCPUIntensive();
        // 主线程保持运行
        System.out.println("Main thread is running. PID: " + ProcessHandle.current().pid());
        Thread.sleep(60000);
    }
}

线程Dump分析工具类

import java.io.*;
import java.util.*;
import java.util.regex.*;
public class ThreadDumpAnalyzer {
    // 分析结果数据结构
    static class ThreadInfo {
        String name;
        String state;
        String threadId;
        String daemon;
        List<String> stackTrace = new ArrayList<>();
        String lockInfo = "";
        String blockerInfo = "";
    }
    public static void main(String[] args) {
        if (args.length < 1) {
            System.out.println("Usage: java ThreadDumpAnalyzer <thread-dump-file>");
            return;
        }
        try {
            List<ThreadInfo> threads = parseThreadDump(new File(args[0]));
            analyzeThreads(threads);
        } catch (IOException e) {
            System.err.println("Error reading thread dump file: " + e.getMessage());
        }
    }
    // 解析线程Dump文件
    private static List<ThreadInfo> parseThreadDump(File file) throws IOException {
        List<ThreadInfo> threads = new ArrayList<>();
        BufferedReader reader = new BufferedReader(new FileReader(file));
        String line;
        ThreadInfo currentThread = null;
        while ((line = reader.readLine()) != null) {
            if (line.startsWith("\"")) {
                // 新线程开始
                if (currentThread != null) {
                    threads.add(currentThread);
                }
                currentThread = new ThreadInfo();
                parseThreadHeader(line, currentThread);
            } else if (currentThread != null && line.trim().length() > 0) {
                currentThread.stackTrace.add(line.trim());
                if (line.trim().startsWith("- waiting to lock")) {
                    currentThread.lockInfo = line.trim();
                } else if (line.trim().startsWith("- waiting on")) {
                    currentThread.blockerInfo = line.trim();
                }
            }
        }
        if (currentThread != null) {
            threads.add(currentThread);
        }
        reader.close();
        return threads;
    }
    // 解析线程头部信息
    private static void parseThreadHeader(String line, ThreadInfo threadInfo) {
        Pattern pattern = Pattern.compile("\"([^\"]+)\" #(\\d+) (daemon )?prio=\\d+ os_prio=\\d+ tid=(\\w+) nid=(\\w+) (.*)");
        Matcher matcher = pattern.matcher(line);
        if (matcher.find()) {
            threadInfo.name = matcher.group(1);
            threadInfo.threadId = matcher.group(3);
            threadInfo.daemon = matcher.group(2) != null ? "daemon" : "user";
            threadInfo.state = matcher.group(6);
        }
    }
    // 分析线程状态
    private static void analyzeThreads(List<ThreadInfo> threads) {
        Map<String, Integer> stateCount = new HashMap<>();
        List<ThreadInfo> blockedThreads = new ArrayList<>();
        List<ThreadInfo> waitingThreads = new ArrayList<>();
        List<ThreadInfo> runningThreads = new ArrayList<>();
        for (ThreadInfo thread : threads) {
            stateCount.merge(thread.state, 1, Integer::sum);
            if (thread.state.contains("BLOCKED")) {
                blockedThreads.add(thread);
            } else if (thread.state.contains("WAITING")) {
                waitingThreads.add(thread);
            } else if (thread.state.contains("RUNNABLE")) {
                runningThreads.add(thread);
            }
        }
        // 输出统计信息
        System.out.println("========== 线程状态统计 ==========");
        stateCount.forEach((state, count) -> 
            System.out.printf("%-20s: %d\n", state, count));
        // 分析阻塞线程
        if (!blockedThreads.isEmpty()) {
            System.out.println("\n========== 可能的问题 ==========");
            System.out.println("检测到 " + blockedThreads.size() + " 个阻塞线程,可能存在死锁或资源竞争");
            for (ThreadInfo thread : blockedThreads) {
                System.out.println("线程: " + thread.name + " (ID: " + thread.threadId + ")");
                if (!thread.lockInfo.isEmpty()) {
                    System.out.println("等待锁: " + thread.lockInfo);
                }
                System.out.println("最后几个栈帧:");
                for (int i = 0; i < Math.min(5, thread.stackTrace.size()); i++) {
                    System.out.println("  " + thread.stackTrace.get(i));
                }
                System.out.println();
            }
        }
        // 分析等待线程
        if (!waitingThreads.isEmpty()) {
            System.out.println("\n========== 等待线程分析 ==========");
            System.out.println("检测到 " + waitingThreads.size() + " 个等待线程");
            for (ThreadInfo thread : waitingThreads) {
                if (thread.stackTrace.size() > 0) {
                    System.out.println("线程 " + thread.name + " 状态: " + thread.state);
                    System.out.println("  最后栈帧: " + thread.stackTrace.get(0));
                }
            }
        }
        // 分析CPU密集型线程
        System.out.println("\n========== 运行中线程 ==========");
        for (ThreadInfo thread : runningThreads) {
            System.out.println("线程 " + thread.name + " 状态: " + thread.state);
            if (thread.stackTrace.size() > 0) {
                System.out.println("  最后栈帧: " + thread.stackTrace.get(0));
            }
        }
    }
}

实战分析示例

public class ThreadDumpRealAnalysis {
    public static void main(String[] args) {
        String dumpContent = """
        "http-nio-8080-exec-10" #210 daemon prio=5 os_prio=0 tid=0x00007f1a3c0e5000 nid=0x2b3 runnable [0x00007f1a301f9000]
           java.lang.Thread.State: RUNNABLE
            at java.base/java.net.SocketInputStream.socketRead0(Native Method)
            at java.base/java.net.SocketInputStream.socketRead(SocketInputStream.java:115)
            at java.base/java.net.SocketInputStream.read(SocketInputStream.java:168)
            at java.base/java.net.SocketInputStream.read(SocketInputStream.java:140)
            at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:364)
            - locked <0x00000000e825c2d8> (a java.io.BufferedInputStream)
        "Thread-15" #53 daemon prio=5 os_prio=0 tid=0x00007f1a3c0e5000 nid=0x2a1 waiting for monitor entry [0x00007f1a301f9000]
           java.lang.Thread.State: BLOCKED (on object monitor)
            at com.example.service.UserService.getUserById(UserService.java:45)
            - waiting to lock <0x00000000d435d678> (a java.util.concurrent.ConcurrentHashMap$Node)
            at com.example.controller.UserController.getUser(UserController.java:25)
        "GC Thread #0" #7 daemon prio=5 os_prio=0 tid=0x00007f1a3c0e5000 nid=0x2b3 runnable [0x00007f1a301f9000]
           java.lang.Thread.State: RUNNABLE
        """;
        // 保存到临时文件并分析
        try {
            File tempFile = File.createTempFile("thread-dump", ".txt");
            FileWriter writer = new FileWriter(tempFile);
            writer.write(dumpContent);
            writer.close();
            // 调用分析器
            ThreadDumpAnalyzer.main(new String[]{tempFile.getAbsolutePath()});
            tempFile.delete();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

自定义ThreadDump监视工具

import java.lang.management.*;
import java.util.*;
public class ThreadMonitor implements Runnable {
    private volatile boolean running = true;
    private long monitorInterval = 5000; // monitoring interval in ms
    // 获取线程Dump
    public String captureThreadDump() {
        StringBuilder sb = new StringBuilder();
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(true, true);
        sb.append("Thread Dump at: ").append(new Date()).append("\n");
        sb.append("Thread count: ").append(threadMXBean.getThreadCount()).append("\n");
        sb.append("Peak thread count: ").append(threadMXBean.getPeakThreadCount()).append("\n");
        sb.append("Daemon thread count: ").append(threadMXBean.getDaemonThreadCount()).append("\n\n");
        for (ThreadInfo threadInfo : threadInfos) {
            sb.append(formatThreadInfo(threadInfo));
            sb.append("\n");
        }
        return sb.toString();
    }
    // 格式化单个线程信息
    private String formatThreadInfo(ThreadInfo threadInfo) {
        StringBuilder sb = new StringBuilder();
        sb.append("\"").append(threadInfo.getThreadName()).append("\"")
          .append(" id=").append(threadInfo.getThreadId())
          .append(" state=").append(threadInfo.getThreadState())
          .append("\n");
        Mockito:
        StackTraceElement[] stackTrace = threadInfo.getStackTrace();
        for (StackTraceElement element : stackTrace) {
            sb.append("    at ").append(element.toString()).append("\n");
        }
        if (threadInfo.getLockName() != null) {
            sb.append("    - 持有锁: ").append(threadInfo.getLockName()).append("\n");
        }
        if (threadInfo.getLockOwnerName() != null) {
            sb.append("    - 等待锁: ").append(threadInfo.getLockOwnerName()).append("\n");
        }
        return sb.toString();
    }
    @Override
    public void run() {
        while (running) {
            try {
                String dump = captureThreadDump();
                System.out.println(dump);
                System.out.println("----------------------------------------");
                Thread.sleep(monitorInterval);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }
    public void stop() {
        running = false;
    }
    public static void main(String[] args) {
        ThreadMonitor monitor = new ThreadMonitor();
        Thread monitorThread = new Thread(monitor, "Thread-Monitor");
        monitorThread.setDaemon(true);
        monitorThread.start();
        // 保持主线程运行
        try {
            Thread.sleep(30000); // Run for 30 seconds
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        monitor.stop();
    }
}

分析脚本示例

#!/bin/bash
# analyze_thread_dump.sh
echo "======= Thread Dump Analysis Script ======="
# 获取Java进程PID
PID=$(pgrep -f "java.*YourApplication")
if [ -z "$PID" ]; then
    echo "No Java process found"
    exit 1
fi
echo "Found Java process with PID: $PID"
# 生成线程Dump
jstack $PID > /tmp/thread_dump_$(date +%Y%m%d_%H%M%S).txt
# 分析阻塞线程
echo "======= Blocked Threads ======="
grep -A 5 "java.lang.Thread.State: BLOCKED" /tmp/thread_dump_*.txt | head -50
# 分析等待线程
echo "======= Waiting Threads ======="
grep -A 5 "java.lang.Thread.State: WAITING" /tmp/thread_dump_*.txt | head -50
# 检查死锁
echo "======= Deadlock Detection ======="
jstack -l $PID 2>&1 | grep -A 10 "Found one Java-level deadlock"
echo "======= Analysis Complete ======="

使用步骤

# 1. 编译并运行示例应用
javac ThreadDumpAnalysisExample.java
java ThreadDumpAnalysisExample
# 2. 获取进程PID
jps -l | grep ThreadDumpAnalysisExample
# 3. 生成线程Dump
jstack <PID> > /tmp/thread_dump.txt
# 4. 分析线程Dump
javac ThreadDumpAnalyzer.java
java ThreadDumpAnalyzer /tmp/thread_dump.txt

这个完整的线程Dump分析案例涵盖了:

  1. Dump生成:多种方式生成线程Dump文件
  2. 场景模拟:模拟死锁、线程阻塞、CPU密集型任务
  3. 解析工具:自动解析和分析线程状态
  4. 实时监控:Java程序内部实时监控线程状态
  5. 分析报告:生成详细的统计和分析结果

通过这个案例,您可以:

  • 快速定位死锁问题
  • 发现线程池过小导致的阻塞
  • 识别CPU密集型线程
  • 监控内存泄漏迹象
  • 优化线程使用效率

抱歉,评论功能暂时关闭!