Отримайте список усіх потоків, які зараз працюють на Java


232

Чи я можу отримати список усіх запущених потоків у поточному JVM (включаючи теми, не запущені моїм класом)?

Чи можливо також отримати Threadі Classоб'єкти всіх потоків у списку?

Я хочу мати можливість це зробити за допомогою коду.

Відповіді:


325

Щоб отримати ітерабельний набір:

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

19
Незважаючи на те, що набагато чіткіше, ніж інша запропонована альтернатива, це призводить до зниження витрат на отримання слідів стека для всіх потоків. Якщо ви все одно будете використовувати ці сліди стека, це явно краще. Якщо ні, то це може бути значно повільнішим, не отримуючи іншого, крім чистого коду.
Едді

29
@Eddie Це припущення від здорового глузду, чи ти робив експерименти? "значно повільніше" ви говорите; наскільки повільніше? Чи варто того? Я сумніваюся в будь-якій спробі зробити код гіршим заради ефективності. Якщо у вас є вимоги до ефективності та інфраструктури для кількісного вимірювання ефективності, я все в порядку, коли люди погіршують код, оскільки вони, здається, знають, що роблять. Побачити корінь усього зла за Дональдом Кнутом.
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: Насправді я згоден - я думаю, що ваша відповідь набагато краща, і, мабуть, це була б прийнята відповідь в першу чергу, якби не пізніше одного року. Якщо ОП все ще часто відвідує так, що він, мабуть, робить, йому б радили не прийняти мою відповідь і скоріше прийняти вашу.
Фріріх Раабе

2
Зауважте, що для чогось іншого, окрім rootGroup, ви повинні використовувати new Thread[rootGroup.activeCount()+1]. activeCount()може бути нульовим, і якщо він є, ви наткнетеся на нескінченний цикл.
jmiserez

7
@thejoshwolfe Я вважаю, що це рішення набагато дешевше.
Хаожун

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

29

Так, погляньте на отримання списку тем . Багато прикладів на цій сторінці.

Це потрібно робити програмно. Якщо ви просто хочете, щоб список в Linux був принаймні, ви можете просто скористатися цією командою:

kill -3 processid

і VM зробить потік дамп для stdout.


5
вбити -3? Принаймні в моєму Linux, це "термінальний вихід". Вбиває, не перераховує.
Майкл Х.

5
Клетус справді правильний - вбивця -3 потік дамп у stdout, незалежно від того, що сигнал повинен означати. Я б подумав замість цього використовувати jstack.
Ден Хардікер

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


14

Ви подивилися на jconsole ?

Тут буде перераховано всі потоки, що працюють для певного процесу Java.

Ви можете запустити jconsole з папки бін 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 не визначено для теми. І я не бачу цієї функції в документації.

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 в TDAs (Thread Dump Analyzer), такий інструмент для швидкої прошивки чи спотифікації потоку .


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.