1. Обзор
Поток — это основная единица параллелизма в Java. В большинстве случаев пропускная способность приложения увеличивается, когда создается несколько потоков для параллельного выполнения задач.
Однако всегда есть точка насыщения. В конце концов, пропускная способность приложения зависит от ресурсов процессора и памяти. После определенного предела увеличение количества потоков может привести к переполнению памяти, переключению контекста потока и т. д.
Таким образом, хорошей отправной точкой при устранении неполадок с нехваткой памяти в приложении Java является мониторинг количества потоков. В этом руководстве мы рассмотрим некоторые способы проверки количества потоков, созданных процессом Java.
2. Графические средства мониторинга Java
Самый простой способ увидеть количество потоков в Java — использовать графический инструмент, такой как Java VisualVM . Помимо потоков приложения, Java VisualVM также перечисляет GC или любые другие потоки, используемые приложением, такие как потоки JMX .
Кроме того, он также показывает статистику, такую как состояния потоков, а также их продолжительность:
Мониторинг количества потоков — самая основная функция 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 .