Rufen Sie eine Liste aller Threads ab, die derzeit in Java ausgeführt werden

232

Gibt es eine Möglichkeit, eine Liste aller laufenden Threads in der aktuellen JVM (einschließlich der Threads) abzurufen? nicht von meiner Klasse gestartet wurden)?

Ist es auch möglich das zu bekommen Thread und ClassObjekte aller Threads in der Liste abzurufen?

Ich möchte dies durch Code tun können.

Kryten
quelle

Antworten:

325

So erhalten Sie einen iterierbaren Satz:

Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
thejoshwolfe
quelle
19
Dies ist zwar viel sauberer als die andere vorgeschlagene Alternative, hat jedoch den Nachteil, dass die Kosten für das Abrufen von Stapelspuren für alle Threads anfallen. Wenn Sie diese Stapelspuren trotzdem verwenden, ist dies eindeutig überlegen. Wenn nicht, kann dies für keinen anderen Gewinn als sauberen Code erheblich langsamer sein.
Eddie
29
@Eddie Ist das eine Annahme aus dem gesunden Menschenverstand oder hast du Experimente gemacht? "deutlich langsamer" sagen Sie; wie viel langsamer? Lohnt es sich? Ich bezweifle jeden Versuch, den Code aus Gründen der Effizienz zu verschlechtern. Wenn Sie eine Effizienzanforderung und eine Infrastruktur haben, um die Effizienz quantitativ zu messen, bin ich damit einverstanden, dass Leute Code verschlimmern, weil sie zu wissen scheinen, was sie tun. Sehen Sie die Wurzel allen Übels nach Donald Knuth.
Thejoshwolfe
20
Ich habe diese spezifischen Alternativen nicht zeitlich festgelegt, aber ich habe mit anderen Java-Methoden zum Sammeln von Stapelspuren im Vergleich zu nur einer Liste von Threads gearbeitet. Die Auswirkungen auf die Leistung scheinen sehr stark davon abzuhängen, welche JVM Sie verwenden (z. B. JRockit vs Sun JVM). Es lohnt sich, in Ihrem speziellen Fall zu messen. Ob dies Auswirkungen auf Sie hat oder nicht, hängt von Ihrer JVM-Auswahl und der Anzahl Ihrer Threads ab. Ich habe festgestellt, dass das Abrufen aller Stack-Traces über ThreadMXBean.dumpAllThreads für etwa 250 Threads 150 bis 200 ms dauert, während nur die Liste der Threads (ohne Traces) nicht messbar ist (0 ms).
Eddie
4
Auf meinem System (Oracle Java 1.7 VM) zeigt eine schnelle Überprüfung, dass diese Methode etwa 70,80-mal langsamer ist als die unten stehende Alternative. Stapelspuren und Reflexionen gehören zu den schwersten Java-Operationen.
Franz D.
5
@thejoshwolfe: Natürlich ist die Lesbarkeit ein wichtiger Faktor, und man sollte nicht mikrooptimieren usw. Ich habe jedoch meine Recherchen durchgeführt, während ich einen kleinen Anwendungsleistungsmonitor geschrieben habe. Für diese Art von Tool ist ein minimaler Leistungsabdruck unerlässlich, um zuverlässige Daten zu erhalten. Daher habe ich mich für die Methode ohne Stapelverfolgung entschieden.
Franz D.
75

Holen Sie sich einen Griff zur Wurzel ThreadGroup, wie folgt:

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

Rufen Sie nun die enumerate()Funktion für die Stammgruppe wiederholt auf. Mit dem zweiten Argument können Sie alle Threads rekursiv abrufen:

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

Beachten Sie, wie wir enumerate () wiederholt aufrufen, bis das Array groß genug ist, um alle Einträge zu enthalten.

Frerich Raabe
quelle
22
Ich bin schockiert, dass diese Strategie im Internet so beliebt ist. Meine Strategie ist viel einfacher (1 Codezeile) und funktioniert genauso gut mit dem zusätzlichen Bonus, Rennbedingungen zu vermeiden.
Thejoshwolfe
11
@thejoshwolfe: Eigentlich stimme ich zu - ich denke, Ihre Antwort ist viel besser, und es wäre wahrscheinlich die akzeptierte Antwort gewesen, wenn es nicht ein Jahr zu spät gewesen wäre. Wenn das OP immer noch SO besucht, was er anscheinend tut, wäre er gut beraten, meine Antwort nicht zu akzeptieren und Ihre eher zu akzeptieren.
Frerich Raabe
2
Beachten Sie, dass Sie für alles andere als das verwenden rootGroupsollten new Thread[rootGroup.activeCount()+1]. activeCount()könnte Null sein, und wenn ja, werden Sie in eine Endlosschleife geraten.
jmiserez
7
@thejoshwolfe Ich nehme an, diese Lösung ist viel billiger.
Haozhun
19
+1 für diese unterschätzte Antwort, da sie meiner Meinung nach viel besser für Überwachungszwecke geeignet ist. Die inhärenten Rennbedingungen spielen bei der Überwachung keine große Rolle. Wie einige schnelle und dreißig Tests gezeigt haben, ist es jedoch etwa 70-80-mal schneller als die auf Stacktraces basierende Lösung. Für die Überwachung ist ein kleiner Leistungsabdruck unerlässlich, da Sie die Auswirkungen auf das überwachte System so gering wie möglich halten möchten (Heisenberg schlägt erneut zu :) Für das Debuggen, bei dem Sie möglicherweise zuverlässigere Informationen benötigen, kann die Stacktrace-Methode verwendet werden wesentlich. Übrigens ist die MxBean-Lösung noch langsamer als die Verwendung von Stacktraces.
Franz D.
29

Ja, sehen Sie sich eine Liste der Themen an . Viele Beispiele auf dieser Seite.

Das ist programmgesteuert. Wenn Sie nur eine Liste unter Linux wünschen, können Sie einfach diesen Befehl verwenden:

kill -3 processid

und die VM führt einen Thread-Dump für stdout durch.

Cletus
quelle
5
-3 töten? Zumindest unter Linux ist das "Terminal Quit". Tötet, listet nicht auf.
Michael H.
5
cletus ist in der Tat richtig - ein kill -3 führt einen Dump auf stdout, unabhängig davon, was das Signal bedeuten soll. Ich würde stattdessen jstack verwenden.
Dan Hardiker
Eine Liste der Threads kann nicht erreicht werden: nadeausoftware.com hat die Verbindung abgelehnt.
DSlomer64
14

Haben Sie sich jconsole angesehen? ?

Dadurch werden alle Threads aufgelistet, die für einen bestimmten Java-Prozess ausgeführt werden.

Sie können jconsole über den Ordner JDK bin starten.

Sie können auch eine vollständige Stapelverfolgung für alle Threads erhalten, indem Sie Ctrl+Breakin Windows klicken oder kill pid --QUITLinux senden .

pjp
quelle
Ich möchte auf die Liste innerhalb meiner Java-Klasse zugreifen
Kryten
In diesem Fall schauen Sie sich die Antwort von Cletus an.
pjp
3
Ähm, warum stimmen die Leute darüber ab, als der Typ sagte, er wolle eine programmatische Lösung?
Cletus
Weil die Frage das nicht sagt. Ich werde die Frage bearbeiten, um sie explizit zu machen.
pjp
8

Apache Commons-Benutzer können verwenden ThreadUtils. Die aktuelle Implementierung verwendet den zuvor beschriebenen Ansatz "Walk the Thread Group".

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

Sie können so etwas ausprobieren:

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

und Sie können natürlich mehr Fadencharakteristik erhalten, wenn Sie benötigen.

Hasskell
quelle
5

In Groovy können Sie private Methoden aufrufen

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

In Java können Sie diese Methode mithilfe von Reflection aufrufen, sofern der Sicherheitsmanager dies zulässt.

Jarek Przygódzki
quelle
Ich erhalte eine Fehlermeldung, getThreads nicht für Thread definiert. Und ich sehe diese Funktion nicht in der Dokumentation.
4

Code-Snippet, um eine Liste der Threads zu erhalten, die vom Haupt-Thread gestartet wurden:

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

Ausgabe:

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

Wenn Sie alle Threads einschließlich Systemthreads benötigen, die nicht von Ihrem Programm gestartet wurden, entfernen Sie die folgende Bedingung.

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

Jetzt ausgeben:

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
quelle
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
quelle
3

Drücken Sie in der Java-Konsole Strg-Pause . Es werden alle Threads sowie einige Informationen zum Heap aufgelistet. Dadurch erhalten Sie natürlich keinen Zugriff auf die Objekte. Aber es kann trotzdem sehr hilfreich beim Debuggen sein.

raoulsson
quelle
1

Mit dem folgenden Befehl können Sie eine Liste der Threads und ihrer vollständigen Status mithilfe des Terminals abrufen:

jstack -l <PID>

Welche PID ist die ID des Prozesses, der auf Ihrem Computer ausgeführt wird? Um die Prozess-ID Ihres Java-Prozesses abzurufen, können Sie einfach den jpsBefehl ausführen .

Sie können auch Ihren Thread-Dump analysieren, der von jstack in TDAs (Thread Dump Analyzer) wie einem Fastthread- oder Spotify-Thread-Analyzer-Tool erstellt wurde .

Amir Fo
quelle