I work on a big Java service that does lots of things. When I snapshot the application’s threads I can see it’s got lots going on:

Talking RPC and HTTP

Running cron jobs and job queue jobs

Persisting to MySQL

Coordinating with ZooKeeper

Collecting garbage

At a glance I can see what the service is doing: what’s blocked on I/O, what’s executing, what’s waiting for locks, and what’s idle.

Analysis is easier if the threads have descriptive names:

connection-mgmt-[twilio.com:443]

job-queue-outgoing-email-0

zk-lb-lease/publisher-outgoing_sms-0

And it’s difficult otherwise:

pool-1-thread-3

pool-21-thread-99

pool-2-thread-1

Naming Threads

The best names help you to know out which class started the thread ( connection-mgmt ) and what that thread is currently doing ( twilio.com:443 ).

If you’re using Guava, just use ThreadFactoryBuilder. Otherwise use this:

public static ThreadFactory threadFactory( final String name, final boolean daemon) { return new ThreadFactory() { @Override public Thread newThread(Runnable runnable) { Thread result = new Thread(runnable, name); result.setDaemon(daemon); return result; } }; }

When your runnable has more context than it’s shared executor, you can use something like OkHttp’s NamedRunnable:

executor.execute(new NamedRunnable("OkHttp Window Update %s", hostname) { @Override public void execute() { writer.windowUpdate(streamId, unacknowledgedBytesRead); } });

Seeing your threads with jstack

The payoff comes when you run jstack . It’s a JDK program that’s sitting the same bin/ directory as java and javac . It will show you the threads of any of the Java programs you’re running.

For example, I can see IntelliJ’s threads by getting its process ID from ps and then passing that to jstack .

$ ps aux | grep idea jwilson 25395 0.0 11.5 10863464 1922108 ?? S 1:11PM 82:09.53 /Applications/IntelliJ IDEA CE.app/Contents/MacOS/idea ... $ jstack 25395 2017-02-04 12:56:19 Full thread dump OpenJDK 64-Bit Server VM (25.112-b6 mixed mode): "ApplicationImpl pooled thread 311" #2168 prio=4 os_prio=31 tid=0x00007fe035058000 nid=0x1a2d7 waiting on condition [0x000070000ffb3000] java.lang.Thread.State: TIMED_WAITING (parking) at sun.misc.Unsafe.park(Native Method) ... "Attach Listener" #2167 daemon prio=9 os_prio=31 tid=0x00007fe02b7bf800 nid=0x1e687 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "process reaper" #2126 daemon prio=10 os_prio=31 tid=0x00007fe03021c800 nid=0x1d957 runnable [0x0000700012441000] java.lang.Thread.State: RUNNABLE at java.lang.UNIXProcess.waitForProcessExit(Native Method) ...

Make Debugging Easier

If you’re creating threads, give ’em names. It’ll make it easier to understand what’s going on in development and to diagnose problems in production.