Uzyskaj listę wszystkich wątków aktualnie uruchomionych w Javie


232

Czy jest jakiś sposób, aby uzyskać listę wszystkich działających wątków w bieżącej maszynie JVM (w tym wątki, które nie zostały uruchomione przez moją klasę)?

Czy możliwe jest również uzyskanie Threadi Classobiektów wszystkich wątków na liście?

Chcę móc to zrobić za pomocą kodu.

Odpowiedzi:


325

Aby uzyskać iterowalny zestaw:

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

19
Chociaż znacznie czystszy niż inna proponowana alternatywa, ma to jednak wadę, że wiąże się z kosztem uzyskania śladów stosu dla wszystkich wątków. Jeśli i tak będziesz używać tych śladów stosu, jest to wyraźnie lepsza opcja. Jeśli nie, może to być znacznie wolniejsze bez żadnego innego zysku niż czysty kod.
Eddie,

29
@Eddie Czy to założenie ze zdrowego rozsądku, czy przeprowadzałeś eksperymenty? mówisz „znacznie wolniej”; o ile wolniej? Czy warto? Podważam każdą próbę pogorszenia kodu ze względu na wydajność. Jeśli masz wymagania dotyczące wydajności i infrastrukturę do mierzenia wydajności ilościowo, to jestem w porządku z ludźmi, którzy pogarszają kod, ponieważ zdają się wiedzieć, co robią. Zobacz źródło wszelkiego zła według Donalda Knutha.
thejoshwolfe

20
Nie określiłem tych konkretnych alternatyw, ale pracowałem z innymi metodami Java zbierania śladów stosu zamiast tylko listy wątków. Wydaje się, że wpływ na wydajność zależy bardzo mocno od używanej maszyny JVM (na przykład JRockit vs. Sun JVM). Warto zmierzyć w konkretnym przypadku. To, czy wpłynie to na ciebie, zależy od twojego wyboru JVM i od liczby posiadanych wątków. Przekonałem się, że pobieranie wszystkich śladów stosu za pośrednictwem ThreadMXBean.dumpAllThreads dla około 250 wątków zajmuje 150-200 ms, a sama lista wątków (bez śladów) nie jest mierzalna (0 ms).
Eddie

4
W moim systemie (Oracle Java 1.7 VM) szybkie sprawdzenie pokazuje, że ta metoda jest ~ 70..80 razy wolniejsza niż alternatywna poniżej. Ślady stosu i odbicie należą do najcięższych operacji Java.
Franz D.

5
@thejoshwolfe: Oczywiście, czytelność jest ważnym czynnikiem i nie należy mikrooptymalizować itp. Jednak zrobiłem badania podczas pisania małego monitora wydajności aplikacji. W przypadku tego rodzaju narzędzia minimalny wpływ na wydajność jest niezbędny do uzyskania wiarygodnych danych, dlatego wybrałem metodę bez stosu.
Franz D.

75

Uzyskaj uchwyt do katalogu głównego ThreadGroup, w ten sposób:

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

Teraz enumerate()kilkakrotnie wywoływaj funkcję w grupie głównej. Drugi argument pozwala uzyskać rekurencyjnie wszystkie wątki:

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

Zwróć uwagę, jak wywołujemy enumerate (), aż tablica będzie wystarczająco duża, aby pomieścić wszystkie wpisy.


22
Jestem zszokowany, że ta strategia jest tak popularna w Internecie. Moja strategia jest znacznie prostsza (1 linia kodu) i działa równie dobrze z dodatkową zaletą unikania warunków wyścigu.
thejoshwolfe

11
@thejoshwolfe: Właściwie zgadzam się - myślę, że twoja odpowiedź jest znacznie lepsza i prawdopodobnie byłaby to odpowiedź zaakceptowana, gdyby nie spóźnił się o rok. Jeśli OP nadal będzie się zgadzać z SO, co najwyraźniej tak robi, dobrze byłoby odrzucić moją odpowiedź i raczej przyjąć twoją.
Frerich Raabe

2
Pamiętaj, że do wszystkiego innego niż rootGrouppowinieneś użyć new Thread[rootGroup.activeCount()+1]. activeCount()może wynosić zero, a jeśli tak, to wpadniesz w nieskończoną pętlę.
jmiserez

7
@ theheoshoshwolfe Podejrzewam, że to rozwiązanie jest znacznie tańsze.
Haozhun

19
+1 za tę niedocenianą odpowiedź, ponieważ jest ona bardziej odpowiednia do celów monitorowania IMHO. Jego naturalne warunki wyścigowe nie mają większego znaczenia w monitorowaniu. Jednak, jak wykazały niektóre szybkie testy „około trzydzieści”, jest to około 70–80 razy szybsze niż rozwiązanie oparte na stacktrace. Do monitorowania niezbędny jest niewielki odcisk wydajności, ponieważ chcesz zachować możliwie jak najmniejszy wpływ na monitorowany system (Heisenberg uderza ponownie :) W przypadku debugowania, gdzie możesz potrzebować bardziej wiarygodnych informacji, można zastosować metodę stacktrace kluczowy. BTW, rozwiązanie MxBean jest nawet wolniejsze niż przy użyciu stacktraces.
Franz D.

29

Tak, spójrz na listę wątków . Wiele przykładów na tej stronie.

To zrobić to programowo. Jeśli chcesz tylko listę w systemie Linux, możesz po prostu użyć tego polecenia:

kill -3 processid

a maszyna wirtualna wykona zrzut wątku na standardowe wyjście.


5
zabić -3? Przynajmniej na moim Linuksie to „terminal quit”. Zabija, nie wymienia.
Michael H.

5
cletus jest rzeczywiście poprawny - kill -3 spowoduje zrzucenie wątku na standardowe wyjście, niezależnie od tego, co ten sygnał ma znaczyć. Zastanowiłbym się nad użyciem jstacka.
Dan Hardiker,

nie można uzyskać listy wątków : nadeausoftware.com odmówiło połączenia.
DSlomer64


14

Spojrzałeś na jconsole ?

Spowoduje to wyświetlenie listy wszystkich wątków uruchomionych dla określonego procesu Java.

Możesz uruchomić jconsole z folderu bin JDK.

Możesz także uzyskać pełny stos śledzenia dla wszystkich wątków, naciskając Ctrl+Breakw systemie Windows lub wysyłając kill pid --QUITw systemie Linux.


Chcę uzyskać dostęp do listy w mojej klasie java
Kryten

W takim przypadku spójrz na odpowiedź Cletusa.
pjp

3
Dlaczego ludzie głosują na to, kiedy facet powiedział, że chce programowego rozwiązania?
cletus

Ponieważ pytanie tego nie mówi. Przeredaguję pytanie, aby było wyraźne.
pjp

8

Użytkownicy Apache Commons mogą korzystać ThreadUtils. W bieżącej implementacji zastosowano wcześniej opisane podejście „spacer po grupie wątków”.

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

7

Możesz spróbować czegoś takiego:

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

i możesz oczywiście uzyskać więcej cech wątku, jeśli potrzebujesz.


5

W Groovy możesz wywoływać metody prywatne

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

W Javie można wywołać tę metodę za pomocą odbicia, pod warunkiem, że zezwala na to menedżer bezpieczeństwa.


Dostaję błąd, getThreads nie zdefiniowane dla wątku. I nie widzę tej funkcji w dokumentacji.

4

Fragment kodu, aby uzyskać listę wątków rozpoczynanych od głównego wątku:

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

wynik:

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

Jeśli potrzebujesz wszystkich wątków, w tym wątków systemowych, które nie zostały uruchomione przez program, usuń poniższy warunek.

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

Teraz wyjście:

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

W konsoli Java naciśnij Ctrl-Break . Spowoduje to wyświetlenie listy wszystkich wątków oraz niektórych informacji o stercie. To oczywiście nie da ci dostępu do obiektów. Ale i tak może być bardzo pomocne przy debugowaniu.


1

Aby uzyskać listę wątków i ich pełnych stanów za pomocą terminala, możesz użyć następującego polecenia:

jstack -l <PID>

Który PID jest identyfikatorem procesu uruchomionego na twoim komputerze. Aby uzyskać identyfikator procesu java, wystarczy uruchomić jpspolecenie.

Ponadto możesz analizować zrzut wątku wygenerowany przez jstack w TDA (Thread Dump Analyzer), taki jak narzędzie szybkiej analizy wątku lub spotify .


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.