Перейти к основному содержимому

Как получить количество потоков в процессе Java

· 6 мин. чтения

1. Обзор

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

Однако всегда есть точка насыщения. В конце концов, пропускная способность приложения зависит от ресурсов процессора и памяти. После определенного предела увеличение количества потоков может привести к переполнению памяти, переключению контекста потока и т. д.

Таким образом, хорошей отправной точкой при устранении неполадок с нехваткой памяти в приложении Java является мониторинг количества потоков. В этом руководстве мы рассмотрим некоторые способы проверки количества потоков, созданных процессом Java.

2. Графические средства мониторинга Java

Самый простой способ увидеть количество потоков в Java — использовать графический инструмент, такой как Java VisualVM . Помимо потоков приложения, Java VisualVM также перечисляет GC или любые другие потоки, используемые приложением, такие как потоки JMX .

Кроме того, он также показывает статистику, такую как состояния потоков, а также их продолжительность:

./3cca169636224b7d96ceb87288515a47.png

Мониторинг количества потоков — самая основная функция Java VisualVM. Вообще говоря, графические инструменты более продвинуты и позволяют отслеживать приложение в реальном времени. Например, Java VisualVM позволяет нам отбирать трассировки стека ЦП и, таким образом, находить класс или метод, которые могут вызвать узкое место ЦП.

Java VisualVM распространяется вместе с установкой JDK на компьютерах с Windows. Для приложений, развернутых в Linux, нам необходимо удаленно подключиться к приложению. Для этого требуются аргументы виртуальной машины JMX .

Поэтому такие инструменты не будут работать, если приложение уже запущено без этих параметров. В следующем разделе мы увидим, как мы можем получить количество потоков с помощью инструментов командной строки.

3. API-интерфейсы Java

В некоторых случаях нам может понадобиться узнать количество потоков внутри самого приложения. Например, для отображения на панелях мониторинга или в журналах.

В таких случаях мы полагаемся на API-интерфейсы Java, чтобы получить количество потоков. К счастью, в классе Thread есть API activeCount() : ``

public class FindNumberofThreads {
public static void main(String[] args) {
System.out.println("Number of threads " + Thread.activeCount());
}
}

И вывод будет:

Number of threads 2

Примечательно, что если мы увидим количество потоков в Java VisualVM, мы увидим больше потоков для одного и того же приложения. Это связано с тем, что activeCount() возвращает только количество потоков в одной группе ThreadGroup . Java делит все потоки на группы для облегчения управления.

В этом примере у нас есть только родительская группа ThreadGroup, т.е. main:

public static void main(String[] args) {
System.out.println("Current Thread Group - " + Thread.currentThread().getThreadGroup().getName());
}
Current Thread Group - main

Если в Java-приложении много групп потоков, функция activeCount() не даст правильного результата. Например, он не вернет количество потоков GC.

В таких сценариях мы можем использовать JMX API :

public static void main(String[] args) {
System.out.println("Total Number of threads " + ManagementFactory.getThreadMXBean().getThreadCount());
}

Этот API возвращает общее количество потоков из всех групп потоков, GC, JMX и т. д.:

Total Number of threads 6

Фактически, графические инструменты JMX, такие как Java VisualVM, используют один и тот же API для своих данных.

4. Инструменты командной строки

Ранее мы обсуждали Java VisualVM, графический инструмент для анализа живых потоков в приложении. Хотя это отличный инструмент для визуализации потоков в реальном времени, он оказывает незначительное влияние на производительность приложения. И, следовательно, это не рекомендуется для производственных сред .

Более того, как мы уже говорили, Java VisualVM требует удаленного подключения в Linux. И ведь в некоторых случаях требует дополнительной настройки. Например, приложение, работающее внутри Docker или Kubernetes, потребует дополнительной настройки службы и порта.

В таких случаях мы должны полагаться на инструменты командной строки в хост-среде, чтобы получить количество потоков.

К счастью, в Java есть несколько команд для создания дампа потока . Мы можем проанализировать дамп потока либо как текстовый файл, либо использовать инструмент анализатора дампа потока, чтобы проверить количество потоков вместе с их состоянием.

Alibaba Arthas — еще один отличный инструмент командной строки, который не требует удаленного подключения или какой-либо специальной настройки.

Кроме того, мы можем получить информацию о потоках из нескольких команд Linux. Например, мы можем использовать команду top для отображения всех потоков любого Java-приложения :

top -H -p 1

Здесь -H — это параметр командной строки для отображения каждого потока в процессе Java. Без этого флага команда top будет отображать объединенную статистику для всех потоков в процессе. Параметр -p фильтрует вывод по идентификатору процесса целевого приложения:

top - 15:59:44 up 7 days, 19:23,  0 users,  load average: 0.52, 0.41, 0.36
Threads: 37 total, 0 running, 37 sleeping, 0 stopped, 0 zombie
%Cpu(s): 3.2 us, 2.2 sy, 0.0 ni, 93.4 id, 0.8 wa, 0.0 hi, 0.3 si, 0.0 st
MiB Mem : 1989.2 total, 110.2 free, 1183.1 used, 695.8 buff/cache
MiB Swap: 1024.0 total, 993.0 free, 31.0 used. 838.8 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 flink 20 0 2612160 304084 29784 S 0.0 14.9 0:00.07 java
275 flink 20 0 2612160 304084 29784 S 0.0 14.9 0:02.87 java
276 flink 20 0 2612160 304084 29784 S 0.0 14.9 0:00.37 VM Thread
277 flink 20 0 2612160 304084 29784 S 0.0 14.9 0:00.00 Reference Handl
278 flink 20 0 2612160 304084 29784 S 0.0 14.9 0:00.00 Finalizer
279 flink 20 0 2612160 304084 29784 S 0.0 14.9 0:00.00 Signal Dispatch

Как видно выше, он показывает идентификатор потока, т . е. PID и использование ЦП и памяти для каждого потока. Подобно Java VisualVM, команда top выведет список всех потоков, включая GC, JMX или любой другой подпроцесс.

Чтобы найти идентификатор процесса, который мы использовали в качестве аргумента в приведенной выше команде, мы можем использовать команду ps :

ps -ef | grep java

На самом деле, мы также можем использовать команду ps для вывода списка потоков:

ps -e -T | grep 1

Параметр -T сообщает команде ps список всех потоков, запущенных приложением:

1     1 ?        00:00:00 java
1 275 ? 00:00:02 java
1 276 ? 00:00:00 VM Thread
1 277 ? 00:00:00 Reference Handl
1 278 ? 00:00:00 Finalizer
1 279 ? 00:00:00 Signal Dispatch
1 280 ? 00:00:03 C2 CompilerThre
1 281 ? 00:00:01 C1 CompilerThre

Здесь первый столбец — это PID, а второй столбец показывает идентификатор потока Linux для каждого потока.

5. Вывод

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

Однако в некоторых ситуациях нам также могут понадобиться графические инструменты, такие как Java VisualVM. Все примеры кода доступны на GitHub .