
Java Thread Dump: VisualVM, jstack, kill -3, jcmd Explained
When your Java application starts behaving unpredictably—threads hanging, CPU usage spiking, or the application becoming unresponsive—you need a thread dump to see what’s happening under the hood. A thread dump is essentially a snapshot of all threads running in a Java Virtual Machine at a specific moment, showing their state, stack traces, and what they’re doing. This post walks you through four essential methods for generating thread dumps: VisualVM’s GUI approach, the reliable jstack command, the old-school kill -3 signal, and the modern jcmd utility. You’ll learn when to use each tool, how to interpret the output, and common troubleshooting scenarios you’ll encounter in production environments.
What is a Java Thread Dump and Why You Need It
A thread dump captures the execution state of every thread in a JVM process at a specific point in time. Think of it as taking a photograph of your application’s internal activity—you can see which threads are running, waiting, blocked, or deadlocked.
Each thread dump entry contains:
- Thread name and ID
- Thread state (RUNNABLE, BLOCKED, WAITING, etc.)
- Stack trace showing the current execution path
- Monitor information for synchronization
- Native thread ID for correlation with OS-level tools
Common scenarios where thread dumps become invaluable:
- Diagnosing deadlocks between threads
- Identifying performance bottlenecks and blocked threads
- Analyzing thread pool utilization
- Debugging infinite loops or hung processes
- Understanding application behavior under load
Method 1: VisualVM – The Visual Approach
VisualVM provides the most user-friendly way to generate and analyze thread dumps through its graphical interface. It’s particularly useful when you need to correlate thread behavior with other metrics like memory usage or CPU consumption.
Setting Up VisualVM
VisualVM comes bundled with Oracle JDK distributions or can be downloaded separately. For JDK 9+, you’ll need to download it independently from the official VisualVM website.
# Launch VisualVM
$JAVA_HOME/bin/jvisualvm
# Or if installed separately
visualvm
Generating Thread Dumps with VisualVM
Once VisualVM is running:
- Navigate to the “Applications” panel on the left
- Locate your Java process (local or remote)
- Right-click the process and select “Thread Dump”
- The dump appears in a new tab with syntax highlighting
VisualVM’s thread dump viewer offers several advantages:
- Color-coded thread states for quick visual scanning
- Built-in deadlock detection with highlighted problem areas
- Thread filtering and search capabilities
- Integration with profiling data
Monitoring Threads in Real-Time
The “Threads” tab in VisualVM provides a timeline view showing thread activity over time. This helps identify patterns like:
- Threads that frequently switch between states
- Long-running operations
- Thread pool starvation
Method 2: jstack – The Command Line Workhorse
jstack is the go-to command-line tool for generating thread dumps, especially in production environments where GUI tools aren’t available. It’s reliable, fast, and available in all standard JDK installations.
Basic jstack Usage
First, identify your Java process ID:
# List all Java processes
jps -v
# Or use ps with grep
ps aux | grep java
Generate a thread dump:
# Basic thread dump
jstack
# Force thread dump (useful for hung processes)
jstack -F
# Include additional information
jstack -l
Practical jstack Examples
Save thread dump to file with timestamp:
# Single thread dump
jstack 12345 > threaddump_$(date +%Y%m%d_%H%M%S).txt
# Multiple dumps with interval (useful for trend analysis)
for i in {1..5}; do
jstack 12345 > threaddump_${i}_$(date +%Y%m%d_%H%M%S).txt
sleep 10
done
When jstack fails with “Unable to open socket file”, try:
# Run as the same user as the Java process
sudo -u jstack
# Or use force mode
jstack -F
jstack Output Analysis
A typical jstack output looks like this:
2024-01-15 10:30:15
Full thread dump Java HotSpot(TM) 64-Bit Server VM (17.0.1+12-LTS-39):
"http-nio-8080-exec-1" #25 daemon prio=5 os_prio=0 tid=0x00007f8b8c028000 nid=0x1a2b waiting on condition [0x00007f8b7c3fd000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x000000076ab62208> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:107)
Method 3: kill -3 – The Unix Signal Method
The kill -3 command sends a SIGQUIT signal to the Java process, instructing it to generate a thread dump. This method works reliably across Unix-like systems and doesn’t require additional JDK tools.
Using kill -3
# Send SIGQUIT signal
kill -3
# Alternative syntax
kill -QUIT
The thread dump output goes to wherever the JVM directs its standard error stream:
- Application logs (if configured)
- Console output (for interactive processes)
- System logs like /var/log/messages
Locating kill -3 Output
Common locations to check:
# Check application logs
tail -f /path/to/application.log
# Check system logs
sudo journalctl -f -u your-java-service
# For Tomcat applications
tail -f $CATALINA_HOME/logs/catalina.out
# Check stderr redirection
ls -la /proc//fd/2
kill -3 Best Practices
- Always verify the process ID before sending the signal
- Monitor disk space—thread dumps can be large in applications with many threads
- Use kill -3 when other tools fail or aren’t available
- Combine with log rotation to prevent log file overflow
Configure log rotation for thread dumps:
# Example logrotate configuration
/var/log/myapp/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
copytruncate
}
Method 4: jcmd – The Modern Swiss Army Knife
jcmd is the most versatile and modern tool for JVM diagnostics, replacing several older utilities. It provides thread dumps plus additional diagnostic capabilities, making it the preferred choice for comprehensive troubleshooting.
Basic jcmd Operations
# List all Java processes
jcmd
# List available commands for a specific process
jcmd help
# Generate thread dump
jcmd Thread.print
# Thread dump with additional lock information
jcmd Thread.print -l
Advanced jcmd Features
jcmd offers capabilities beyond simple thread dumps:
# VM classloader statistics
jcmd VM.classloader_stats
# GC information
jcmd GC.run
jcmd GC.class_histogram
# System properties
jcmd VM.system_properties
# JVM flags
jcmd VM.flags
# Performance counters
jcmd PerfCounter.print
jcmd Thread Dump Analysis
jcmd provides enhanced thread dump information:
# Comprehensive thread analysis
jcmd Thread.print -l > comprehensive_dump.txt
# Example output includes:
# - Locked ownable synchronizers
# - Detailed lock information
# - Thread CPU time
# - Allocated memory per thread
Tool Comparison and When to Use Each
Tool | Best Use Case | Pros | Cons | Availability |
---|---|---|---|---|
VisualVM | Development, interactive analysis | GUI interface, visual timeline, integrated profiling | Requires X11 forwarding for remote use, resource intensive | JDK 6-8 bundled, separate download for JDK 9+ |
jstack | Production troubleshooting, scripting | Lightweight, reliable, force mode available | Limited output format, older tool | All JDK versions |
kill -3 | Emergency situations, minimal toolset | Always available on Unix, no JDK tools needed | Output location varies, can’t control format | Unix/Linux systems only |
jcmd | Comprehensive analysis, modern environments | Multiple diagnostic features, detailed output | Not available in older JDK versions | JDK 7+ |
Real-World Troubleshooting Scenarios
Scenario 1: Deadlock Detection
When your application hangs completely, multiple thread dumps taken 10 seconds apart help identify deadlocks:
# Automated deadlock detection script
#!/bin/bash
PID=$1
for i in {1..3}; do
echo "=== Thread dump $i at $(date) ===" >> deadlock_analysis.txt
jcmd $PID Thread.print >> deadlock_analysis.txt
sleep 10
done
# Analyze for deadlock patterns
grep -A 10 -B 5 "Found Java-level deadlock" deadlock_analysis.txt
Scenario 2: High CPU Usage Investigation
Correlate high CPU threads with Java threads:
# 1. Find high CPU threads
top -H -p
# 2. Convert thread ID to hex
printf "%x\n"
# 3. Generate thread dump
jstack > cpu_investigation.txt
# 4. Search for the hex thread ID (nid) in dump
grep -A 20 "nid=0x" cpu_investigation.txt
Scenario 3: Memory Leak Through Thread Analysis
Combine thread dumps with heap analysis:
# Generate both thread and heap dump
jcmd Thread.print > threads.txt
jcmd GC.class_histogram > heap_classes.txt
# Look for accumulating thread patterns
grep -c "java.lang.Thread.State: WAITING" threads.txt
Best Practices and Common Pitfalls
Thread Dump Collection Best Practices
- Take multiple dumps: Single dumps show a moment in time; series reveal patterns
- Include timestamps: Always timestamp your dumps for correlation
- Monitor disk space: Large applications can generate multi-megabyte dumps
- Document context: Note what the application was doing when the dump was taken
- Use consistent intervals: 10-30 second intervals work well for most scenarios
Common Pitfalls to Avoid
- Wrong process ID: Always verify with jps before taking dumps
- Insufficient permissions: Run as the same user as the Java process
- Overloading the system: Don’t take dumps too frequently on production systems
- Ignoring GC threads: JVM internal threads can provide important clues
- Not checking for core dumps: Force dumps with -F can sometimes crash unhealthy processes
Thread Dump Analysis Tips
Focus on these key indicators:
# Thread states to investigate:
# BLOCKED - waiting for monitor lock
# WAITING - waiting for notification
# TIMED_WAITING - waiting with timeout
# RUNNABLE - executing or ready to execute
# Common problematic patterns:
grep -c "java.lang.Thread.State: BLOCKED" threaddump.txt
grep -c "parking to wait for" threaddump.txt
grep -c "waiting for monitor entry" threaddump.txt
Integration with Monitoring and Automation
Automated Thread Dump Collection
Set up automated collection based on system metrics:
#!/bin/bash
# Auto-collect thread dumps when CPU exceeds threshold
JAVA_PID=$(pgrep -f "your-application")
CPU_USAGE=$(ps -p $JAVA_PID -o %cpu --no-headers)
if (( $(echo "$CPU_USAGE > 80" | bc -l) )); then
DUMP_FILE="auto_threaddump_$(date +%Y%m%d_%H%M%S).txt"
jcmd $JAVA_PID Thread.print > $DUMP_FILE
echo "High CPU detected: $CPU_USAGE%. Thread dump saved to $DUMP_FILE"
fi
Integration with APM Tools
Many Application Performance Monitoring tools can trigger thread dump collection:
- New Relic’s thread profiler integration
- AppDynamics thread dump automation
- Custom Prometheus/Grafana alerting with script execution
- ELK stack integration for thread dump log analysis
Thread dumps are essential tools for Java application troubleshooting, and each method—VisualVM, jstack, kill -3, and jcmd—has its place in your diagnostic toolkit. Start with jcmd for modern JVMs when you need comprehensive information, fall back to jstack for reliable command-line access, use kill -3 in emergencies, and leverage VisualVM when you need visual analysis during development. Remember that effective thread dump analysis often requires multiple samples and correlation with other system metrics to identify the root cause of performance issues.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.