Получить список всех потоков, работающих в настоящее время в Java


232

Можно ли как-нибудь получить список всех запущенных потоков в текущей JVM (включая потоки, не запущенные моим классом)?

Можно ли также получить объекты Threadи Classвсех потоков в списке?

Я хочу быть в состоянии сделать это с помощью кода.

Ответы:


325

Чтобы получить повторяемый набор:

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

19
Несмотря на то, что он намного чище, чем предлагаемая другая альтернатива, у него есть и обратная сторона: затраты на получение трассировки стека для всех потоков. Если вы все равно будете использовать эти трассировки стека, это явно лучше. Если нет, то это может быть значительно медленнее, если не получить ничего, кроме чистого кода.
Эдди

29
@ Эдди Это предположение из здравого смысла, или ты делал эксперименты? "значительно медленнее", говорите вы; насколько медленнее? Стоит ли оно того? Я ставлю под сомнение любые попытки сделать код хуже для эффективности. Если у вас есть требования к эффективности и инфраструктура для количественного измерения эффективности, тогда я согласен с тем, что люди делают код хуже, потому что они, кажется, знают, что делают. Посмотрите на корень всего зла, согласно Дональду Кнуту.
thejoshwolfe

20
Я не рассчитывал эти конкретные альтернативы, но я работал с другими средствами Java, собирающими трассировки стека, а не просто список потоков. Влияние на производительность очень сильно зависит от того, какую JVM вы используете (например, JRockit против Sun JVM). Это стоит измерить в вашем конкретном случае. Будет ли это влиять на вас, зависит от вашего выбора JVM и от того, сколько у вас потоков. Я обнаружил, что получение всех трассировок стека с помощью ThreadMXBean.dumpAllThreads для примерно 250 потоков занимает 150-200 мсек при получении только списка потоков (без трасс), который невозможно измерить (0 мсек).
Эдди

4
В моей системе (Oracle Java 1.7 VM) быстрая проверка показывает, что этот метод в 70–80 раз медленнее, чем альтернатива ниже. Следы стека и отражение относятся к самым тяжелым операциям Java.
Франц Д.

5
@thejoshwolfe: Конечно, удобочитаемость является важным фактором, поэтому не нужно микрооптимизировать и т. д. Однако я провел исследование, когда писал небольшой монитор производительности приложений. Для такого рода инструментов необходим минимальный отпечаток производительности для получения надежных данных, поэтому я выбрал метод без использования стека.
Франц Д.

75

Получить дескриптор к корню ThreadGroup, как это:

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

Теперь enumerate()повторно вызовите функцию в корневой группе. Второй аргумент позволяет получить все потоки рекурсивно:

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

Обратите внимание, как мы неоднократно вызываем enumerate (), пока массив не станет достаточно большим, чтобы содержать все записи.


22
Я в шоке, что эта стратегия так популярна в интернете. Моя стратегия намного проще (1 строка кода) и работает так же хорошо с дополнительным бонусом избегания условий гонки.
thejoshwolfe

11
@thejoshwolfe: На самом деле, я согласен - я думаю, что ваш ответ намного лучше, и, вероятно, это был бы принятый ответ в первую очередь, если бы не было одного года с опозданием. Если ОП по-прежнему часто посещает SO, что он, по-видимому, делает, ему бы посоветовали не принять мой ответ и скорее принять ваш.
Фрерих Раабе

2
Обратите внимание, что для чего-либо, кроме rootGroup, вы должны использовать new Thread[rootGroup.activeCount()+1]. activeCount()может быть ноль, и если это так, вы столкнетесь с бесконечным циклом.
jmiserez

7
@thejoshwolfe Полагаю, это решение намного дешевле.
Хаожун

19
+1 за этот недооцененный ответ, так как он гораздо больше подходит для целей мониторинга ИМХО. Присущие ему гоночные условия не имеют большого значения для мониторинга. Однако, как показал какой-то быстрый и грязный тест, он примерно в 70-80 раз быстрее, чем решение на основе стековой трассировки. Для мониторинга важен небольшой отпечаток производительности, так как вы хотите, чтобы влияние на отслеживаемую систему было как можно меньшим (Гейзенберг наносит удар снова :) Для отладки, когда вам может потребоваться более надежная информация, может использоваться метод стековой трассировки. существенный. Кстати, решение MxBean даже медленнее, чем использование стековых трасс.
Франц Д.

29

Да, взгляните на получение списка тем . Много примеров на этой странице.

Это делается программно. Если вы просто хотите получить список в Linux, по крайней мере, вы можете просто использовать эту команду:

kill -3 processid

и виртуальная машина сделает дамп потока в стандартный вывод.


5
убить -3? По крайней мере, на моем linux, это "терминал ушел". Убивает, не перечисляет.
Майкл Х.

5
cletus действительно верен - команда kill -3 будет направлять дамп на стандартный вывод независимо от того, что должен означать сигнал. Я хотел бы рассмотреть возможность использования Jstack вместо.
Дэн Хардикер

невозможно получить список тем : nadeausoftware.com отказался подключиться.
DSlomer64


14

Вы смотрели на jconsole ?

Это перечислит все потоки, работающие для определенного процесса Java.

Вы можете запустить jconsole из папки bin JDK.

Вы также можете получить полную трассировку стека для всех потоков, нажав Ctrl+Breakв Windows или отправив kill pid --QUITв Linux.


Я хочу получить доступ к списку в моем классе Java
Kryten

В таком случае посмотрите на ответ Клита.
pjp

3
Хм, почему люди голосуют за это, когда парень сказал, что хочет программного решения?
Клет

Потому что в вопросе этого не говорится. Я отредактирую вопрос, чтобы сделать его явным.
pjp

8

Пользователи Apache Commons могут использовать ThreadUtils. Текущая реализация использует ранее описанный подход с использованием групповых потоков.

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

7

Вы можете попробовать что-то вроде этого:

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

и вы можете, очевидно, получить больше характеристик потока, если вам нужно.


5

В Groovy вы можете вызывать приватные методы

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

В Java вы можете вызывать этот метод, используя отражение, если это разрешено диспетчером безопасности.


Я получаю ошибку, getThreads не определен для Thread. И я не вижу эту функцию в документации.

4

Фрагмент кода, чтобы получить список потоков, запущенных основным потоком:

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

вывод:

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

Если вам нужны все потоки, включая системные, которые не были запущены вашей программой, удалите условие ниже.

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

Теперь вывод:

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

В консоли Java нажмите Ctrl-Break . В нем будут перечислены все потоки плюс некоторая информация о куче. Это не даст вам доступ к объектам, конечно. Но это может быть очень полезно для отладки в любом случае.


1

Чтобы получить список потоков и их полных состояний с помощью терминала, вы можете использовать команду ниже:

jstack -l <PID>

Какой PID является идентификатором процесса, запущенного на вашем компьютере. Чтобы получить идентификатор процесса вашего Java-процесса, вы можете просто запустить jpsкоманду.

Кроме того, вы можете проанализировать дамп потока, созданный jstack в TDA (Thread Dump Analyzer), с помощью такого инструмента быстрого анализа потока или спрайтов .


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.