Um thread dump é um instantâneo de toda thread de uma JVM em execução e de exatamente onde cada uma está na sua pilha de chamadas. É o artefato mais útil que existe quando uma aplicação Java trava, gruda um núcleo de CPU, para de atender requisições ou vai lentamente parando — as pilhas dizem o que cada thread está de fato fazendo naquele instante. A boa notícia é que capturar um leva poucos segundos e não exige reinício, profiler nem mudança de código. Este guia cobre toda forma confiável de tirar um, em qualquer SO e em container.
Quando você precisa de um thread dump
Recorra a um thread dump sempre que a JVM estiver viva mas se comportando mal: requisições dão timeout mas o processo está de pé, um pool de threads parece exaurido, a CPU fica presa em 100% sem causa óbvia, ou o app dá deadlock. O dump mostra o estado de cada thread (RUNNABLE, BLOCKED, WAITING, TIMED_WAITING), o lock que cada thread bloqueada espera e qual thread o segura — suficiente para identificar um deadlock ou um acúmulo de contenção de lock diretamente.
Descubra o PID da JVM (jps)
Todo método de captura precisa do process id da JVM alvo. O JDK traz o jps exatamente para isso — ele lista os processos Java e suas classes main ou nomes de jar, então você distingue o seu:
jps -l # 4821 com.example.MyApplication # 4977 org.jetbrains.jps.cmdline.Launcher # 5012 jdk.jcmd/sun.tools.jps.Jps # -l = nome completo de pacote/jar, -v = mostra as flags da JVM
Aqui o app é o pid 4821. Se o jps não estiver no PATH, ps -ef | grep java (Linux/macOS) ou o Gerenciador de Tarefas (Windows) também servem. Note que o jps só enxerga JVMs do mesmo usuário — use sudo -u <user> jps para alcançar o processo de outro usuário.
jstack <pid> — o padrão
O jstack é a ferramenta clássica e dedicada. Aponte-o para o pid e ele imprime o dump completo no standard output — redirecione para um arquivo:
jstack 4821 > dump.txt # -l adiciona info de locks: ownable synchronizers (ReentrantLock, etc.) # e uma secao de deadlock. Use-a a menos que tenha um motivo para nao usar. jstack -l 4821 > dump.txt # -F forca um dump de uma JVM travada/irresponsiva (best effort) jstack -F 4821 > dump.txt
Vale transformar a flag -l (long) em hábito: ela anexa a lista de locks que cada thread possui e um relatório dedicado de deadlock, que é exatamente o que você precisa quando threads estão BLOCKED umas nas outras.
jcmd <pid> Thread.print
O jcmd é o comando de diagnóstico moderno e de propósito geral da JVM, e o que a equipe do JDK hoje recomenda. O Thread.print produz o dump idêntico:
jcmd 4821 Thread.print > dump.txt # -l para ownable synchronizers travados, igual ao jstack -l jcmd 4821 Thread.print -l > dump.txt # Dump moderno de virtual threads (Project Loom), JSON, JDK 21+: jcmd 4821 Thread.dump_to_file -format=json vthreads.json
A última forma é a que você usa numa aplicação com virtual threads: Thread.dump_to_file enumera as virtual threads (que um jstack clássico não mostra por completo) e sua saída JSON é fácil de parsear por ferramentas.
kill -3 — sem ferramentas instaladas
Se as ferramentas de linha de comando do JDK não estiverem disponíveis (um JRE enxuto, uma máquina travada), você ainda pode pedir o dump à própria JVM enviando o sinal QUIT:
kill -3 4821 # ou, por nome: kill -3 $(pgrep -f MyApplication)
A pegadinha importante: kill -3 não escreve um arquivo. A JVM imprime o dump no próprio stdout/console. Se você a iniciou com java -jar app.jar > app.log 2>&1, o dump aparece no fim do app.log; sob um container vai para os logs do container; sob systemd, para o journal. Se o stdout for descartado, o dump se perde — então prefira jstack/jcmd quando puder. O kill -3 é seguro: não encerra o processo.
No Windows
jstack e jcmd funcionam de forma idêntica no Windows — pegue o pid do jps ou do Gerenciador de Tarefas e rode os mesmos comandos. Não existe kill -3; o equivalente do sinal é o Ctrl-Break na janela de console onde uma JVM em primeiro plano está rodando, o que imprime o dump nesse console:
jps -l jstack 4821 > dump.txt rem ou, para uma JVM em primeiro plano, foque o console dela e pressione: Ctrl + Break
Para uma JVM rodando como serviço do Windows ou em background, Ctrl-Break não é opção — use jstack ou jcmd com o pid.
Spring Boot Actuator
Uma aplicação Spring Boot com o Actuator no classpath pode expor um thread dump por HTTP — útil quando você não tem acesso ao shell do host mas alcança a porta de management. Habilite o endpoint e chame:
# application.properties
management.endpoints.web.exposure.include=threaddump
# depois:
curl http://localhost:8080/actuator/threaddump # JSON
curl -H 'Accept: text/plain' \
http://localhost:8080/actuator/threaddump > dump.txt # texto no formato jstackA variante text/plain retorna o familiar formato jstack. Proteja esse endpoint — um thread dump pode vazar detalhe interno, então mantenha a porta de management do Actuator privada ou protegida.
Dentro de um container (jattach)
Num container enxuto a JVM costuma ser o pid 1 e as ferramentas do JDK muitas vezes não estão. Dois caminhos confiáveis:
- Se o JDK estiver presente, entre no container e rode o comando normal:
docker exec <container> jcmd 1 Thread.print. - Se só houver JRE, use o
jattach— um binário estático minúsculo que fala o protocolo de attach da JVM sem o JDK completo:jattach 1 threaddump > dump.txt. Ele também dispara dumps no estilokill -3e funciona quando o alvo roda como o mesmo usuário.
Kubernetes é a mesma ideia: kubectl exec <pod> -- jcmd 1 Thread.print > dump.txt. Como um restart apaga a evidência, capture o dump antes de o pod ser reciclado.
Capture vários dumps, não um
Um único thread dump é um quadro congelado. Ele não distingue uma thread brevemente estacionada de uma genuinamente emperrada. Capture três a cinco dumps, com cinco a dez segundos de intervalo, e compare:
for i in 1 2 3 4 5; do jstack -l 4821 > dump-$i.txt sleep 7 done
Threads que ficam no mesmo frame de pilha em todos os dumps são as que estão de fato travadas — um travamento, um deadlock ou um lock atrás do qual todos se enfileiram. Threads que se movem entre os dumps só estão trabalhando. Essa comparação é toda a diferença entre perseguir um alarme falso e achar a thread que está segurando tudo.
O que fazer com o dump
Uma vez com o arquivo em mãos, ler alguns milhares de frames de pilha na unha é lento e fácil de errar. O ThreadMine parseia dumps de HotSpot, OpenJ9, Zing e GraalVM, detecta deadlocks, thread leaks, picos de CPU e exaustão de pool automaticamente e — quando você joga uma sequência de dumps — alinha-os numa timeline para que as threads que nunca se movem saltem à vista na hora. Não é preciso cadastro para analisar um dump; cole e receba a resposta.
Conclusão
Capturar um thread dump nunca é a parte difícil. Ache o pid com jps, depois use jstack -l <pid> ou jcmd <pid> Thread.print como padrão; kill -3 ou Ctrl-Break quando não há ferramentas instaladas; o endpoint do Actuator quando você só tem HTTP; e o jattach dentro de um container. Capture vários dumps com poucos segundos de intervalo, e deixe a leitura ser a parte que você automatiza.
Perguntas frequentes
Como capturo um thread dump em Java?
O jeito mais simples é jstack <pid>, que imprime o stack trace de toda thread no stdout. Ache o pid com jps -l, depois rode jstack -l <pid> > dump.txt (a flag -l adiciona informação de locks e ownable synchronizers). jcmd <pid> Thread.print faz o mesmo e é a ferramenta moderna recomendada. Se você não puder instalar as ferramentas do JDK, kill -3 <pid> envia o sinal QUIT à JVM e ela imprime um dump no próprio stdout/console.
Qual a diferença entre jstack e jcmd?
Os dois produzem o mesmo thread dump. jcmd é o comando de diagnóstico mais novo e de propósito geral, e é o que a equipe do JDK recomenda; jstack é a ferramenta dedicada mais antiga e às vezes é marcada como deprecada para opções avançadas. Para um thread dump simples, jcmd <pid> Thread.print e jstack <pid> são intercambiáveis. O jcmd também gera um dump moderno de virtual threads com Thread.dump_to_file -format=json.
Como capturo um thread dump no Windows?
Use jstack <pid> ou jcmd <pid> Thread.print exatamente como no Linux — pegue o pid do jps ou do Gerenciador de Tarefas. Não existe kill -3 no Windows; o equivalente do sinal é pressionar Ctrl-Break na janela de console onde a JVM roda em primeiro plano, o que imprime o dump nesse console. jstack/jcmd são a escolha confiável para uma JVM em background ou serviço.
Onde o kill -3 manda o thread dump?
kill -3 <pid> (SIGQUIT) não cria arquivo. A JVM escreve o dump no próprio standard output — onde quer que o console do processo esteja direcionado. Para um app iniciado com java -jar app.jar > app.log, o dump cai em app.log; num container vai para os logs do container; num serviço pode ir para o log do serviço ou se perder se o stdout for descartado. Por isso jstack/jcmd, que escrevem no seu terminal, costumam ser mais fáceis.
Quantos thread dumps devo capturar?
Capture pelo menos três a cinco, com cinco a dez segundos de intervalo. Um dump só é um instantâneo e não distingue uma thread que está brevemente estacionada de uma que está genuinamente travada. Comparar vários dumps mostra quais threads nunca se movem (um travamento ou deadlock real) versus quais só estão ocupadas — a diferença entre um alarme falso e o problema de verdade.
Quer ver tudo isso aplicado ao seu dump?
Faça upload e tenha health score, problemas detectados e sugestões em segundos. Sem cadastro para o primeiro dump.