Ottieni un elenco di tutti i thread attualmente in esecuzione in Java


232

Esiste un modo per ottenere un elenco di tutti i thread in esecuzione nella JVM corrente (inclusi i thread non avviati dalla mia classe)?

È anche possibile ottenere gli oggetti Threade Classdi tutti i thread nell'elenco?

Voglio essere in grado di farlo attraverso il codice.

Risposte:


325

Per ottenere un set iterabile:

Set<Thread> threadSet = Thread.getAllStackTraces().keySet();

19
Sebbene molto più pulito dell'altra alternativa proposta, questo ha il rovescio della medaglia nel sostenere il costo di ottenere tracce di stack per tutti i thread. Se userete comunque quelle tracce dello stack, questo è chiaramente superiore. In caso contrario, questo potrebbe essere significativamente più lento per nessun guadagno diverso dal codice pulito.
Eddie,

29
@Eddie È un'ipotesi di buon senso o hai fatto esperimenti? "significativamente più lento" dici; quanto più lento? Ne vale la pena? Metto in dubbio qualsiasi tentativo di peggiorare il codice per motivi di efficienza. Se hai un requisito di efficienza e un'infrastruttura per misurare quantitativamente l'efficienza, allora sto bene con le persone che peggiorano il codice, perché sembrano sapere cosa stanno facendo. Vedi la radice di tutti i mali secondo Donald Knuth.
thejoshwolfe,

20
Non ho cronometrato queste alternative specifiche, ma ho lavorato con altri mezzi Java per raccogliere tracce dello stack contro solo un elenco di thread. L'impatto sulle prestazioni sembra dipendere fortemente da quale JVM si sta utilizzando (ad esempio JRockit vs Sun JVM). Vale la pena misurare nella tua specifica istanza. Se ti influenzerà o meno dipende dalla tua scelta JVM e da quanti thread hai. Ho scoperto che ottenere tutte le tracce dello stack tramite ThreadMXBean.dumpAllThreads per circa 250 thread richiede 150-200 msec mentre non è possibile misurare solo l'elenco dei thread (senza tracce) (0 msec).
Eddie,

4
Sul mio sistema (Oracle Java 1.7 VM), un rapido controllo mostra che questo metodo è ~ 70..80 volte più LENTO dell'alternativa di seguito. Le tracce dello stack e la riflessione appartengono alle operazioni Java più pesanti.
Franz D.

5
@thejoshwolfe: Certo, la leggibilità è un fattore importante, e non si dovrebbe micro-ottimizzare ecc. Tuttavia, ho fatto le mie ricerche mentre scrivevo un piccolo monitor delle prestazioni delle applicazioni. Per questo tipo di strumento, un'impronta minima delle prestazioni è essenziale per ottenere dati affidabili, quindi ho scelto il metodo senza stacktrace.
Franz D.

75

Ottieni un handle per il root ThreadGroup, in questo modo:

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

Ora chiama enumerate()ripetutamente la funzione sul gruppo radice. Il secondo argomento ti consente di ottenere tutti i thread in modo ricorsivo:

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

Nota come chiamiamo enumerate () ripetutamente fino a quando l'array è abbastanza grande da contenere tutte le voci.


22
Sono scioccato dal fatto che questa strategia sia così popolare su Internet. La mia strategia è molto più semplice (1 riga di codice) e funziona altrettanto bene con l'ulteriore vantaggio di evitare le condizioni di gara.
thejoshwolfe,

11
@thejoshwolfe: In realtà, sono d'accordo - penso che la tua risposta sia molto migliore, e probabilmente sarebbe stata la risposta accettata in primo luogo se non fosse arrivata con un anno di ritardo. Se l'OP continua a frequentare SO, cosa che a quanto pare lo fa, sarebbe ben consigliato di non accettare la mia risposta e piuttosto di accettare la tua.
Frerich Raabe,

2
Si noti che per qualsiasi cosa diversa da quella rootGroup, è necessario utilizzare new Thread[rootGroup.activeCount()+1]. activeCount()potrebbe essere zero e, se lo è, ti imbatterai in un ciclo infinito.
jmiserez,

7
@thejoshwolfe Suppongo che questa soluzione sia molto meno costosa.
Haozhun,

19
+1 per questa risposta sottovalutata, in quanto è molto più adatto a scopi di monitoraggio IMHO. Le sue condizioni di gara intrinseche non contano molto nel monitoraggio. Tuttavia, come hanno dimostrato alcuni test quick'n'dirty, è circa 70-80 volte più veloce della soluzione basata su stacktrace. Per il monitoraggio, una piccola impronta delle prestazioni è essenziale, poiché vorrai mantenere gli effetti sul sistema monitorato il più piccolo possibile (Heisenberg colpisce ancora :) Per il debug, dove potresti aver bisogno di informazioni più affidabili, il metodo stacktrace potrebbe essere essenziale. A proposito, la soluzione MxBean è persino più lenta rispetto all'utilizzo di stacktraces.
Franz D.

29

Sì, dai un'occhiata a ottenere un elenco di thread . Molti esempi su quella pagina.

Questo è farlo programmaticamente. Se vuoi solo un elenco su Linux almeno puoi semplicemente usare questo comando:

kill -3 processid

e la VM eseguirà un dump del thread su stdout.


5
uccidere -3? Almeno sul mio Linux, questo è "terminale chiuso". Uccide, non elenca.
Michael H.

5
il cletus è davvero corretto: un'uccisione -3 invierà il dump allo stdout, indipendentemente dal significato del segnale. Considererei invece l'uso di jstack.
Dan Hardiker,

non è possibile ottenere un elenco di thread : nadeausoftware.com ha rifiutato di connettersi.
DSlomer64,


14

Hai dato un'occhiata a jconsole ?

Questo elencherà tutti i thread in esecuzione per un particolare processo Java.

È possibile avviare jconsole dalla cartella bin JDK.

Puoi anche ottenere una traccia dello stack completo per tutti i thread colpendo Ctrl+Breakin Windows o inviando kill pid --QUITin Linux.


Voglio accedere all'elenco della mia lezione di Java
Kryten,

In tal caso, guarda la risposta di Cletus.
pjp,

3
Uhm, perché la gente lo vota quando il tizio ha detto che voleva una soluzione programmatica?
cletus,

Perché la domanda non lo afferma. Modificherò la domanda per renderla esplicita.
pjp,

8

Gli utenti di Apache Commons possono utilizzare ThreadUtils. L'implementazione corrente utilizza l'approccio walk the thread group precedentemente delineato.

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

7

Puoi provare qualcosa del genere:

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

e puoi ovviamente ottenere più caratteristiche del thread se ne hai bisogno.


5

In Groovy puoi chiamare metodi privati

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

In Java , è possibile richiamare quel metodo usando reflection a condizione che il gestore della sicurezza lo consenta.


Ottengo l'errore, getThreads non definito per Thread. E non vedo questa funzione nella documentazione.

4

Snippet di codice per ottenere l'elenco dei thread avviati dal thread principale:

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();
        }
    }
}

produzione:

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 sono necessari tutti i thread, inclusi i thread di sistema, che non sono stati avviati dal programma, rimuovere la condizione seguente.

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

Ora uscita:

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

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 + "  ");
        }
    }

3

Nella console Java, premi Ctrl-Break . Elencherà tutti i thread più alcune informazioni sull'heap. Questo non ti darà accesso agli oggetti ovviamente. Ma può essere molto utile per il debug comunque.


1

Per ottenere un elenco di thread e dei loro stati completi utilizzando il terminale, è possibile utilizzare il comando seguente:

jstack -l <PID>

Quale PID è l'id del processo in esecuzione sul tuo computer. Per ottenere l'id di processo del tuo processo java puoi semplicemente eseguire il jpscomando.

Inoltre, puoi analizzare il tuo dump del thread prodotto da jstack in TDA (Thread Dump Analyzer) come strumento di analisi del thread fastthread o spotify .


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.