- 3 minutes to read

Thread Deadlock Detection

The Nodinite JMX Monitoring Agent doesn't detect thread deadlocks and doesn't count threads. It monitors CPU and free heap per JVM (Configuration). This page explains what a thread deadlock is, what you can and can't expect to see in Nodinite, and how to find a deadlock with standard JVM tools such as jstack and JConsole.

Understanding Thread Deadlocks

A thread deadlock occurs when two or more JVM threads each hold a lock that another thread is waiting to acquire. None of the threads can proceed; they wait indefinitely, and the work they handle stalls. The JVM itself keeps running, and a deadlock doesn't resolve itself: the application usually needs a restart.

graph LR A["fa:fa-lock Thread A
Holds Lock 1
Waiting for Lock 2"] B["fa:fa-lock Thread B
Holds Lock 2
Waiting for Lock 1"] A -->|"waiting for"| B B -->|"waiting for"| A style A fill:#c33d34 style B fill:#c33d34

Diagram: Thread deadlock (red, both threads blocked): Thread A waits for Lock 2 held by Thread B, while Thread B waits for Lock 1 held by Thread A.

Common causes are acquiring several locks in inconsistent order across code paths, nested synchronized blocks, and third-party libraries or connectors whose internal locks conflict with application locks.

What the JMX Monitoring Agent Shows During a Deadlock

Signal Shown by the JMX Monitoring Agent Notes
Deadlocked threads ❌ No The agent doesn't read thread information
Thread count ❌ No The agent doesn't count threads
CPU usage ✅ Yes Blocked threads use little CPU, so a deadlock often doesn't change CPU at all
Free heap ✅ Yes Heap may drop if work queues up behind the blocked threads, but that isn't guaranteed
JVM reachable ✅ Yes The Resource shows Unavailable only if the JVM stops answering JMX, which a deadlock usually doesn't cause

Important

A JVM Resource can stay OK during a deadlock. Don't rely on the JMX Monitoring Agent to catch deadlocks; watch the work the application does instead, for example with Non-Events Monitoring on expected message volumes or the Web Services Monitoring Agent on the application's endpoints.

Finding a Deadlock with JVM Tools

Generate a Thread Dump with jstack

A thread dump captures the state of all JVM threads at a point in time. Run jstack on the JVM host:

# Find the process ID
jps -l

# Write a thread dump to a file
jstack <PID> > thread-dump.txt

Tip

Capture 2–3 thread dumps about 15 seconds apart. Threads that are blocked in every dump are deadlocked or under heavy lock contention.

Read the Thread Dump

When the JVM finds a deadlock, jstack ends the dump with a summary like this:

Found one Java-level deadlock:
=============================
"Thread-A": waiting to lock monitor 0x00000000f8b3c420
  which is held by "Thread-B"
"Thread-B": waiting to lock monitor 0x00000000f8b3c500
  which is held by "Thread-A"

Look for BLOCKED (on object monitor) (the thread waits for a lock), waiting to lock <address>, and locked <address> in the stack trace of each blocked thread.

Use JConsole

JConsole connects to the same JMX remote port that the Nodinite JMX Gateway uses. On the Threads tab, click Detect Deadlock to list deadlocked threads and their stack traces.

Resolving Thread Deadlocks

Restart the JVM to release the locks, then capture a thread dump after startup to confirm the deadlock doesn't reappear at once. To prevent recurring deadlocks:

  • Consistent lock ordering - Always acquire locks in the same order across all code paths.
  • Lock timeouts - Use ReentrantLock.tryLock(timeout) instead of synchronized blocks so a thread gives up instead of waiting forever.
  • Reduce lock scope - Keep the code inside synchronized blocks short.
  • Thread-safe data structures - Use java.util.concurrent collections to reduce explicit locking.

Next Steps

Configuration
OS vs JVM Monitoring

Supported Java Versions
Multi-JVM Monitoring
Heap Used vs Committed
JMX Monitoring Agent
JMX Troubleshooting Overview