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

232

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

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

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

Kryten
источник

Ответы:

325

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

Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
thejoshwolfe
источник
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());
}
gerardw
источник
7

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

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

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

hasskell
источник
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 + "  ");
        }
    }
ZZ Coder
источник
3

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

raoulsson
источник
1

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

jstack -l <PID>

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

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

Амир Фо
источник
0

ManagementFactory.getThreadMXBean().getAllThreadIds()

Мартин Керстен
источник
5
Вы должны дать больше контекста вокруг своего ответа, чтобы он был полезен не только тем, кто задал вопрос, но и всем, кто натыкается на ответ.
Пратик