{"skill":{"slug":"thread-dump-analyzer","displayName":"Thread Dump Analyzer","summary":"Analyze thread dumps and goroutine dumps to diagnose deadlocks, thread pool exhaustion, contention hotspots, and blocked threads. Supports JVM thread dumps,...","description":"---\nname: thread-dump-analyzer\ndescription: Analyze thread dumps and goroutine dumps to diagnose deadlocks, thread pool exhaustion, contention hotspots, and blocked threads. Supports JVM thread dumps, Go goroutine dumps, Python threading dumps, and Node.js async stack traces.\n---\n\n# Thread Dump Analyzer\n\nDiagnose concurrency issues from thread dumps. Find deadlocks, identify contention hotspots, detect thread pool exhaustion, and map blocked/waiting thread chains — across JVM, Go, Python, and Node.js runtimes.\n\nUse when: \"analyze thread dump\", \"application is hanging\", \"deadlock detected\", \"threads are stuck\", \"goroutine leak\", \"connection pool exhausted\", \"thread pool full\", \"application not responding\", or when an application stops processing requests.\n\n## Commands\n\n### 1. `analyze` — Parse and Diagnose Thread Dump\n\n#### Step 1: Capture Thread Dump\n\n**JVM (Java/Kotlin/Scala):**\n```bash\n# Method 1: jstack\njstack $(pgrep -f 'java.*your-app') > /tmp/thread-dump.txt 2>&1\n\n# Method 2: kill -3 (prints to stdout/stderr)\nkill -3 $(pgrep -f 'java.*your-app')\n\n# Method 3: jcmd\njcmd $(pgrep -f 'java.*your-app') Thread.print > /tmp/thread-dump.txt\n```\n\n**Go:**\n```bash\n# Method 1: SIGQUIT (prints all goroutines to stderr)\nkill -QUIT $(pgrep -f 'your-go-app')\n\n# Method 2: pprof endpoint\ncurl -s http://localhost:6060/debug/pprof/goroutine?debug=2 > /tmp/goroutine-dump.txt\n\n# Method 3: runtime.Stack()\ncurl -s http://localhost:6060/debug/pprof/goroutine?debug=1 | head -50\n```\n\n**Python:**\n```bash\n# Method 1: faulthandler\nkill -USR1 $(pgrep -f 'python.*your-app')\n\n# Method 2: programmatic\npython3 -c \"\nimport threading, traceback, sys\nfor thread_id, frame in sys._current_frames().items():\n    thread = next((t for t in threading.enumerate() if t.ident == thread_id), None)\n    name = thread.name if thread else 'Unknown'\n    print(f'\\n--- Thread {name} ({thread_id}) ---')\n    traceback.print_stack(frame)\n\"\n```\n\n**Node.js:**\n```bash\n# Async stack traces\nkill -USR1 $(pgrep -f 'node.*your-app')\n# Connect via chrome://inspect and capture\n```\n\n#### Step 2: Parse Thread States\n\nClassify each thread/goroutine:\n\n| State | JVM | Go | Meaning |\n|-------|-----|-----|---------|\n| **RUNNABLE** | RUNNABLE | running | Actively executing |\n| **WAITING** | WAITING/TIMED_WAITING | select/chan receive | Waiting for signal |\n| **BLOCKED** | BLOCKED | semacquire | Waiting for lock |\n| **PARKED** | PARKING | sleep | Suspended |\n| **I/O** | in native | IO wait/syscall | Waiting for I/O |\n\nCount threads by state:\n```\nRUNNABLE: 15 (18%)\nWAITING: 45 (54%)\nBLOCKED: 12 (14%) ⚠️ HIGH\nTIMED_WAITING: 10 (12%)\nPARKED: 2 (2%)\n```\n\nIf BLOCKED > 10% → likely contention issue.\n\n#### Step 3: Detect Deadlocks\n\n**JVM:** Look for \"Found one Java-level deadlock\" in dump output.\n\n**Manual detection (any language):**\n1. Find all BLOCKED threads and what lock they're waiting for\n2. Find who holds each lock\n3. Check for cycles: Thread A waiting for Lock 1 held by Thread B, Thread B waiting for Lock 2 held by Thread A\n\n```\n🔴 DEADLOCK DETECTED:\n  Thread \"worker-1\" BLOCKED waiting for Lock@0x7f3a (held by \"worker-3\")\n  Thread \"worker-3\" BLOCKED waiting for Lock@0x8b2c (held by \"worker-1\")\n  → Circular dependency: worker-1 → Lock@0x7f3a → worker-3 → Lock@0x8b2c → worker-1\n```\n\n#### Step 4: Detect Thread Pool Exhaustion\n\n```\nThread pool \"http-handler\" — 200/200 threads (100% utilized)\n  180 threads BLOCKED on database connection pool\n  15 threads WAITING on external API response\n  5 threads RUNNABLE (processing)\n  \n⚠️ THREAD POOL EXHAUSTED: all handler threads consumed\nRoot cause: database connection pool is the bottleneck\n  → Connection pool max: 20, all 20 in use\n  → Average query time: 2.3s (normally 50ms) — likely slow query or lock contention\n```\n\n#### Step 5: Identify Contention Hotspots\n\nGroup blocked threads by the lock they're waiting on:\n\n```markdown\n## Lock Contention Hotspots\n\n### Lock: DatabaseConnectionPool@0x7f3a — 85 threads waiting\n- Held by: Thread \"worker-42\" (executing SQL query for 15 seconds)\n- Waiters: 85 threads blocked for avg 8.3 seconds\n- Impact: All incoming requests queued\n- Fix: Investigate slow query in worker-42, increase pool size\n\n### Lock: CacheManager@0x8b2c — 12 threads waiting\n- Held by: Thread \"cache-refresh-1\" (loading cache from DB)\n- Waiters: 12 threads blocked for avg 1.2 seconds\n- Impact: Cache reads blocked during refresh\n- Fix: Use read-write lock, or double-buffering for cache refresh\n```\n\n#### Step 6: Generate Report\n\n```markdown\n# Thread Dump Analysis\n\n## Summary\n- Total threads: 215\n- Deadlocks: 0\n- Thread pool utilization: 100% (EXHAUSTED)\n- Top contention: DatabaseConnectionPool (85 blocked threads)\n- Likely root cause: slow query holding all DB connections\n\n## Thread State Distribution\n- RUNNABLE: 15 (7%)\n- BLOCKED: 97 (45%) 🔴\n- WAITING: 85 (40%)\n- TIMED_WAITING: 18 (8%)\n\n## Root Cause Chain\n1. Slow SQL query (15s) holding connection in worker-42\n2. Connection pool (max 20) exhausted — all connections busy\n3. 85 HTTP handler threads blocked waiting for connection\n4. Thread pool (200) exhausted — all threads consumed\n5. New requests rejected with 503\n\n## Recommendations\n1. IMMEDIATE: Kill slow query and investigate (likely missing index)\n2. SHORT-TERM: Add query timeout (5s max)\n3. MEDIUM-TERM: Increase connection pool to 50\n4. LONG-TERM: Add circuit breaker on DB access\n```\n\n### 2. `compare` — Compare Two Thread Dumps\n\nTake dumps at different times and highlight:\n- New blocked threads\n- Threads stuck in same state (not making progress)\n- Growing thread count (leak)\n- Changed contention patterns\n\n### 3. `goroutine-leak` — Detect Go Goroutine Leaks\n\nSpecifically for Go applications:\n- Compare goroutine counts over time\n- Find goroutines stuck in channel receive with no sender\n- Detect context leak (context not cancelled)\n- Find leaked HTTP connections (response body not closed)\n","tags":{"latest":"1.0.0"},"stats":{"comments":0,"downloads":328,"installsAllTime":0,"installsCurrent":0,"stars":0,"versions":1},"createdAt":1777650547930,"updatedAt":1778492821950},"latestVersion":{"version":"1.0.0","createdAt":1777650547930,"changelog":"Initial release of Thread Dump Analyzer.\n\n- Diagnose concurrency issues from thread/goroutine/threading dumps across JVM, Go, Python, and Node.js.\n- Detect deadlocks, thread pool exhaustion, contention hotspots, and blocked threads.\n- Step-by-step commands to analyze thread states, detect deadlocks, and summarize blocked/waiting chains.\n- Generate actionable reports with root cause analysis and recommendations.\n- Compare two thread dumps to spot leaks or changes in thread activity.\n- Special support for Go goroutine leak detection.","license":"MIT-0"},"metadata":null,"owner":{"handle":"charlie-morrison","userId":"s17cttbdxry5kkyafjw983mq8s83p4y3","displayName":"charlie-morrison","image":"https://avatars.githubusercontent.com/u/271589886?v=4"},"moderation":null}