Obtenha uma lista de todos os threads atualmente em execução em Java

232

Existe alguma maneira de obter uma lista de todos os threads em execução na JVM atual (incluindo os threads não iniciados pela minha classe)?

Também é possível obter os objetos Threade Classde todos os threads na lista?

Eu quero ser capaz de fazer isso através do código.

Kryten
fonte

Respostas:

325

Para obter um conjunto iterável:

Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
thejoshwolfe
fonte
19
Embora muito mais limpo do que a outra alternativa proposta, isso tem o lado negativo de incorrer no custo de obter rastreamentos de pilha para todos os encadeamentos. Se você usará esses rastreamentos de pilha de qualquer maneira, isso é claramente superior. Caso contrário, isso pode ser significativamente mais lento, sem nenhum ganho que não seja o código limpo.
Eddie
29
@ Eddie Isso é uma suposição do senso comum, ou você fez experimentos? "significativamente mais lento" você diz; quanto mais lento? Vale a pena? Eu questiono qualquer tentativa de piorar o código por questões de eficiência. Se você tem um requisito de eficiência e uma infra-estrutura para medir quantitativamente a eficiência, estou bem com as pessoas que pioram o código, porque elas parecem saber o que estão fazendo. Veja a raiz de todo mal, de acordo com Donald Knuth.
thejoshwolfe
20
Não cronometrei essas alternativas específicas, mas trabalhei com outros meios Java de reunir rastreamentos de pilha versus apenas uma lista de threads. O impacto no desempenho parece depender fortemente de qual JVM você está usando (JRockit vs Sun JVM, por exemplo). Vale a pena medir em sua instância específica. Se isso afetará você ou não, depende da sua escolha da JVM e de quantos encadeamentos você possui. Eu descobri que a obtenção de todos os rastreamentos de pilha via ThreadMXBean.dumpAllThreads por cerca de 250 threads leva de 150 a 200 mseg, enquanto apenas a lista de threads (sem rastreios) não é mensurável (0 ms).
Eddie
4
No meu sistema (Oracle Java 1.7 VM), uma verificação rápida mostra que esse método é ~ 70..80 vezes MAIS LENTO que a alternativa abaixo. Rastreamentos de pilha e reflexão pertencem às operações Java mais pesadas.
Franz D.
5
@thejoshwolfe: Obviamente, a legibilidade é um fator importante, e não se deve otimizar, etc. No entanto, fiz minha pesquisa enquanto escrevia um pequeno monitor de desempenho de aplicativos. Para esse tipo de ferramenta, uma impressão de desempenho mínima é essencial para obter dados confiáveis, por isso escolhi o método sem rastreamento de pilha.
Franz D.
75

Obtenha um identificador para a raiz ThreadGroup, assim:

ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
ThreadGroup parentGroup;
while ((parentGroup = rootGroup.getParent()) != null) {
    rootGroup = parentGroup;
}

Agora, chame a enumerate()função no grupo raiz repetidamente. O segundo argumento permite obter todos os threads, recursivamente:

Thread[] threads = new Thread[rootGroup.activeCount()];
while (rootGroup.enumerate(threads, true ) == threads.length) {
    threads = new Thread[threads.length * 2];
}

Observe como chamamos enumerate () repetidamente até que a matriz seja grande o suficiente para conter todas as entradas.

Frerich Raabe
fonte
22
Estou chocado que essa estratégia seja tão popular na internet. Minha estratégia é bem mais simples (1 linha de código) e funciona tão bem com o bônus adicional de evitar as condições da corrida.
thejoshwolfe
11
@thejoshwolfe: Na verdade, eu concordo - acho que sua resposta é muito melhor, e provavelmente teria sido a resposta aceita em primeiro lugar, se não fosse um ano atrasado. Se o OP ainda frequenta o SO, o que ele aparentemente faz, é aconselhável que você não aceite minha resposta e aceite a sua.
Frerich Raabe 23/10/12
2
Observe que, para algo diferente de rootGroup, você deve usar new Thread[rootGroup.activeCount()+1]. activeCount()pode ser zero e, se for, você encontrará um loop infinito.
31414 jmiserez
7
@thejoshwolfe Suponho que esta solução seja muito menos cara.
Haozhun 22/08/14
19
+1 para esta resposta subestimada, pois é muito mais adequado para fins de monitoramento do IMHO. Suas condições de corrida inerentes não importam muito no monitoramento. No entanto, como alguns testes rápidos demonstraram, é cerca de 70 a 80 vezes mais rápido que a solução baseada em stacktrace. Para o monitoramento, uma pequena impressão de desempenho é essencial, pois você deseja manter os efeitos no sistema monitorado o menor possível (Heisenberg ataca novamente :) Para depuração, onde você pode precisar de informações mais confiáveis, o método stacktrace pode ser essencial. BTW, a solução MxBean é ainda mais lenta que o uso de stacktraces.
Franz D.
29

Sim, veja como obter uma lista de threads . Muitos exemplos nessa página.

Isso é feito programaticamente. Se você deseja apenas uma lista no Linux, pelo menos, basta usar este comando:

kill -3 processid

e a VM fará um despejo de encadeamento para stdout.

cleto
fonte
5
matar -3? Pelo menos no meu linux, isso é "terminal quit". Mata, não lista.
Michael H.
5
o cletus está realmente correto - um kill -3 encadeará dump em stdout, independentemente do significado do sinal. Eu consideraria usar o jstack.
Dan Hardiker
não é possível acessar uma lista de threads : nadeausoftware.com se recusou a se conectar.
DSlomer64 17/06
14

Você já deu uma olhada no jconsole ?

Isso listará todos os threads em execução para um processo Java específico.

Você pode iniciar o jconsole a partir da pasta bin do JDK.

Você também pode obter um rastreamento de pilha completo para todos os threads pressionando Ctrl+Breakno Windows ou enviando kill pid --QUITno Linux.

pjp
fonte
Eu quero acessar a lista dentro da minha classe java
Kryten
Nesse caso, veja a resposta do cletus.
Pjp
3
Por que as pessoas estão votando nisso quando o cara disse que queria uma solução programática?
Cletus
Porque a pergunta não afirma isso. Vou editar a pergunta para torná-la explícita.
Pjp
8

Os usuários do Apache Commons podem usar ThreadUtils. A implementação atual usa a abordagem do grupo de threads, descrita anteriormente.

for (Thread t : ThreadUtils.getAllThreads()) {
      System.out.println(t.getName() + ", " + t.isDaemon());
}
gerardw
fonte
7

Você pode tentar algo como isto:

Thread.getAllStackTraces().keySet().forEach((t) -> System.out.println(t.getName() + "\nIs Daemon " + t.isDaemon() + "\nIs Alive " + t.isAlive()));

e, obviamente, você pode obter mais características de threads, se precisar.

hasskell
fonte
5

No Groovy, você pode chamar métodos privados

// Get a snapshot of the list of all threads 
Thread[] threads = Thread.getThreads()

Em Java , você pode chamar esse método usando reflexão, desde que o gerenciador de segurança permita.

Jarek Przygódzki
fonte
Eu recebo erro, getThreads não definido para o Thread. E eu não vejo essa função na documentação.
4

Snippet de código para obter a lista de threads iniciada pelo thread principal:

import java.util.Set;

public class ThreadSet {
    public static void main(String args[]) throws Exception{
        Thread.currentThread().setName("ThreadSet");
        for ( int i=0; i< 3; i++){
            Thread t = new Thread(new MyThread());
            t.setName("MyThread:"+i);
            t.start();
        }
        Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
        for ( Thread t : threadSet){
            if ( t.getThreadGroup() == Thread.currentThread().getThreadGroup()){
                System.out.println("Thread :"+t+":"+"state:"+t.getState());
            }
        }
    }
}

class MyThread implements Runnable{
    public void run(){
        try{
            Thread.sleep(5000);
        }catch(Exception err){
            err.printStackTrace();
        }
    }
}

resultado:

Thread :Thread[MyThread:2,5,main]:state:TIMED_WAITING
Thread :Thread[MyThread:0,5,main]:state:TIMED_WAITING
Thread :Thread[MyThread:1,5,main]:state:TIMED_WAITING
Thread :Thread[ThreadSet,5,main]:state:RUNNABLE

Se você precisar de todos os threads, incluindo os do sistema, que não foram iniciados pelo seu programa, remova a condição abaixo.

if ( t.getThreadGroup() == Thread.currentThread().getThreadGroup())

Agora saída:

Thread :Thread[MyThread:2,5,main]:state:TIMED_WAITING
Thread :Thread[Reference Handler,10,system]:state:WAITING
Thread :Thread[MyThread:1,5,main]:state:TIMED_WAITING
Thread :Thread[ThreadSet,5,main]:state:RUNNABLE
Thread :Thread[MyThread:0,5,main]:state:TIMED_WAITING
Thread :Thread[Finalizer,8,system]:state:WAITING
Thread :Thread[Signal Dispatcher,9,system]:state:RUNNABLE
Thread :Thread[Attach Listener,5,system]:state:RUNNABLE
Ravindra babu
fonte
3
    public static void main(String[] args) {


        // Walk up all the way to the root thread group
        ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
        ThreadGroup parent;
        while ((parent = rootGroup.getParent()) != null) {
            rootGroup = parent;
        }

        listThreads(rootGroup, "");
    }


    // List all threads and recursively list all subgroup
    public static void listThreads(ThreadGroup group, String indent) {
        System.out.println(indent + "Group[" + group.getName() + 
                ":" + group.getClass()+"]");
        int nt = group.activeCount();
        Thread[] threads = new Thread[nt*2 + 10]; //nt is not accurate
        nt = group.enumerate(threads, false);

        // List every thread in the group
        for (int i=0; i<nt; i++) {
            Thread t = threads[i];
            System.out.println(indent + "  Thread[" + t.getName() 
                    + ":" + t.getClass() + "]");
        }

        // Recursively list all subgroups
        int ng = group.activeGroupCount();
        ThreadGroup[] groups = new ThreadGroup[ng*2 + 10];
        ng = group.enumerate(groups, false);

        for (int i=0; i<ng; i++) {
            listThreads(groups[i], indent + "  ");
        }
    }
ZZ Coder
fonte
3

No console java, pressione Ctrl-Break . Ele listará todos os threads, além de algumas informações sobre o heap. Isso não permitirá o acesso aos objetos, é claro. Mas pode ser muito útil para depuração de qualquer maneira.

raoulsson
fonte
1

Para obter uma lista de threads e seus estados completos usando o terminal, você pode usar o comando abaixo:

jstack -l <PID>

Qual PID é o ID do processo em execução no seu computador. Para obter o ID do processo java, você pode simplesmente executar o jpscomando

Além disso, você pode analisar seu dump de encadeamento produzido pelo jstack nos TDAs (Thread Dump Analyzer), como a ferramenta fastthread ou o analisador de encadeamento spotify .

Amir Fo
fonte