Hablemos sobre el volcado de hilos y cómo analizarlo.
También discutiremos cómo ayuda identificar los problemas y algunos de los analizadores que puede usar.
What is Thread?
Un proceso es un programa de computadora que se carga en la memoria de la computadora y está en ejecución. Puede ser ejecutado por un procesador o un conjunto de procesadores. Un proceso se describe en la memoria con información importante como almacenes de variables, identificadores de archivos, contador de programa, registros y señales, etc.
Un proceso puede constar de muchos procesos ligeros denominados hilos. Esto ayuda a lograr un paralelismo en el que un proceso se divide en varios subprocesos. Esto da como resultado un mejor rendimiento. Todos los subprocesos de un proceso comparten el mismo espacio de memoria y dependen unos de otros.
Volcados de hilo
Cuando el proceso se está ejecutando, podemos detectar el estado actual de ejecución del subprocesos en el proceso utilizando volcados de subprocesos. Un volcado de subprocesos contiene una instantánea de todos los subprocesos activos en un punto particular durante la ejecución de un programa. Contiene toda la información relevante sobre el hilo y su estado actual.
Hoy en día, una aplicación moderna implica varios subprocesos. Cada hilo requiere ciertos recursos, realiza ciertas actividades relacionadas con el proceso. Esto puede aumentar el rendimiento de una aplicación, ya que los subprocesos pueden utilizar los núcleos de CPU disponibles.
Pero hay compensaciones, por ejemplo, a veces varios subprocesos pueden no coordinarse bien entre sí y puede surgir una situación de punto muerto. Entonces, si algo sale mal, podemos usar volcados de subprocesos para inspeccionar el estado de nuestros subprocesos.
Thread dump in Java
Un volcado de subprocesos de JVM es una lista del estado de todos los subprocesos que forman parte del proceso en ese momento específico. Contiene información sobre la pila del hilo, presentada como un seguimiento de pila. Como está escrito en texto plano, el contenido se puede guardar para revisarlo más tarde. El análisis de volcados de subprocesos puede ayudar
- Optimización del rendimiento de JVM
- Optimización del rendimiento de la aplicación
- Diagnóstico de problemas, por ejemplo, un punto muerto, contención de subprocesos, etc.
Generation of Thread Dumps
Hay muchas formas de generar volcados de subprocesos. A continuación se muestran algunas herramientas basadas en JVM y se pueden ejecutar desde la línea de comandos / terminal (herramientas CLI) o /compartimiento (Herramientas GUI) directorio de la carpeta de instalación de Java.
Explorémoslos.
#1. jStack
La forma más sencilla de generar un volcado de subprocesos es mediante jStack. jStack se envía con JVM y se puede usar desde la línea de comandos. Aquí, necesitamos el PID del proceso para el que queremos generar el volcado de hilo. Para obtener PID podemos usar jps comando como se muestra a continuación.
jps -l
jps
enumera todos los identificadores de procesos de Java.
En Windows
C:\Program Files\Java\jdk1.8.0_171\bin>jps -l
47172 portal
6120 sun.tools.jps.Jps
C:\Program Files\Java\jdk1.8.0_171\bin>
En Linux
[geekfkare@localhost ~]# jps -l
1088 /opt/keycloak/jboss-modules.jar
26680 /var/lib/jenkins/workspace/kyc/kyc/target/kyc-1.0.jar
7193 jdk.jcmd/sun.tools.jps.Jps
2058 /usr/share/jenkins/jenkins.war
11933 /var/lib/jenkins/workspace/admin-portal/target/portal-1.0.jar
[geekfkare@localhost ~]#
Como podemos ver aquí, obtenemos una lista de todos los procesos de Java en ejecución. Contiene el ID de VM local para el proceso de Java en ejecución y el nombre de la aplicación en las columnas uno y dos, respectivamente. Ahora, para generar el volcado de hilo, usamos el jStack programa con Lo bandera que crea una salida larga del volcado. También podemos canalizar la salida a algún archivo de texto de nuestra elección.
jstack -l 26680<br>
[geekfkare@localhost ~]# jstack -l 26680
2020-06-27 06:04:53
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.221-b11 mixed mode):
"Attach Listener" #16287 daemon prio=9 os_prio=0 tid=0x00007f0814001800 nid=0x4ff2 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"logback-8" #2316 daemon prio=5 os_prio=0 tid=0x00007f07e0033000 nid=0x4792 waiting on condition [0x00007f07baff8000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000006ca9a1fc0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1081)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Locked ownable synchronizers:
- None
"logback-7" #2315 daemon prio=5 os_prio=0 tid=0x00007f07e0251800 nid=0x4791 waiting on condition [0x00007f07bb0f9000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000006ca9a1fc0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1081)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Locked ownable synchronizers:
- None
#2. jvisualvm
jvisualvm es una herramienta GUI que nos ayuda a solucionar problemas, monitorear y perfilar aplicaciones Java. También viene con JVM y se puede iniciar desde el /compartimiento directorio de nuestra instalación de java. Es muy intuitivo y fácil de usar. Entre otras opciones, también nos permite capturar el volcado de subprocesos para un proceso en particular.
Para ver el volcado de hilo para un proceso en particular, podemos hacer clic derecho en el programa y seleccionar Volcado de hilo desde el menú contextual.

#3. jcmd
JCMD es una utilidad de línea de comandos que se incluye con el JDK y se utiliza para enviar solicitudes de comando de diagnóstico a la JVM.
Sin embargo, solo funciona en la máquina local donde se ejecuta la aplicación Java. Se puede utilizar para controlar las grabaciones de vuelo de Java, diagnosticar y solucionar problemas de aplicaciones Java y JVM. Podemos usar el Thread.print
comando de jcmd para obtener una lista de volcados de subprocesos para un proceso en particular especificado por el PID.
A continuación se muestra un ejemplo de cómo podemos usar jcmd
.
jcmd 28036 Thread.print
C:\Program Files\Java\jdk1.8.0_171\bin>jcmd 28036 Thread.print
28036:
2020-06-27 21:20:02
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.171-b11 mixed mode):
"Bundle File Closer" #14 daemon prio=5 os_prio=0 tid=0x0000000021d1c000 nid=0x1d4c in Object.wait() [0x00000000244ef000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Unknown Source)
at org.eclipse.osgi.framework.eventmgr.EventManager$EventThread.getNextEvent(EventManager.java:403)
- locked <0x000000076f380a88> (a org.eclipse.osgi.framework.eventmgr.EventManager$EventThread)
at org.eclipse.osgi.framework.eventmgr.EventManager$EventThread.run(EventManager.java:339)
"Active Thread: Equinox Container: 0b6cc851-96cd-46de-a92b-253c7f7671b9" #12 prio=5 os_prio=0 tid=0x0000000022e61800 nid=0xbff4 waiting on condition [0x00000000243ee000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x000000076f388188> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(Unknown Source)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(Unknown Source)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
"Service Thread" #10 daemon prio=9 os_prio=0 tid=0x0000000021a7b000 nid=0x2184 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread3" #9 daemon prio=9 os_prio=2 tid=0x00000000219f5000 nid=0x1300 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread2" #8 daemon prio=9 os_prio=2 tid=0x00000000219e0000 nid=0x48f4 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x00000000219df000 nid=0xb314 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x00000000219db800 nid=0x2260 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x00000000219d9000 nid=0x125c waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x00000000219d8000 nid=0x834 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001faf3000 nid=0x36c0 in Object.wait() [0x0000000021eae000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076f390180> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(Unknown Source)
- locked <0x000000076f390180> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(Unknown Source)
at java.lang.ref.Finalizer$FinalizerThread.run(Unknown Source)
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000000005806000 nid=0x13c0 in Object.wait() [0x00000000219af000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076f398178> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Unknown Source)
at java.lang.ref.Reference.tryHandlePending(Unknown Source)
- locked <0x000000076f398178> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Unknown Source)
"main" #1 prio=5 os_prio=0 tid=0x000000000570e800 nid=0xbf8 runnable [0x0000000000fec000]
java.lang.Thread.State: RUNNABLE
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.<init>(Unknown Source)
at java.util.zip.ZipFile.<init>(Unknown Source)
at java.util.zip.ZipFile.<init>(Unknown Source)
at org.eclipse.osgi.framework.util.SecureAction.getZipFile(SecureAction.java:307)
at org.eclipse.osgi.storage.bundlefile.ZipBundleFile.getZipFile(ZipBundleFile.java:136)
at org.eclipse.osgi.storage.bundlefile.ZipBundleFile.lockOpen(ZipBundleFile.java:83)
at org.eclipse.osgi.storage.bundlefile.ZipBundleFile.getEntry(ZipBundleFile.java:290)
at org.eclipse.equinox.weaving.hooks.WeavingBundleFile.getEntry(WeavingBundleFile.java:65)
at org.eclipse.osgi.storage.bundlefile.BundleFileWrapper.getEntry(BundleFileWrapper.java:55)
at org.eclipse.osgi.storage.BundleInfo$Generation.getRawHeaders(BundleInfo.java:130)
- locked <0x000000076f85e348> (a java.lang.Object)
at org.eclipse.osgi.storage.BundleInfo$CachedManifest.get(BundleInfo.java:599)
at org.eclipse.osgi.storage.BundleInfo$CachedManifest.get(BundleInfo.java:1)
at org.eclipse.equinox.weaving.hooks.SupplementerRegistry.addSupplementer(SupplementerRegistry.java:172)
at org.eclipse.equinox.weaving.hooks.WeavingHook.initialize(WeavingHook.java:138)
at org.eclipse.equinox.weaving.hooks.WeavingHook.start(WeavingHook.java:208)
at org.eclipse.osgi.storage.FrameworkExtensionInstaller.startActivator(FrameworkExtensionInstaller.java:261)
at org.eclipse.osgi.storage.FrameworkExtensionInstaller.startExtensionActivators(FrameworkExtensionInstaller.java:198)
at org.eclipse.osgi.internal.framework.SystemBundleActivator.start(SystemBundleActivator.java:112)
at org.eclipse.osgi.internal.framework.BundleContextImpl$3.run(BundleContextImpl.java:815)
at org.eclipse.osgi.internal.framework.BundleContextImpl$3.run(BundleContextImpl.java:1)
at java.security.AccessController.doPrivileged(Native Method)
at org.eclipse.osgi.internal.framework.BundleContextImpl.startActivator(BundleContextImpl.java:808)
at org.eclipse.osgi.internal.framework.BundleContextImpl.start(BundleContextImpl.java:765)
at org.eclipse.osgi.internal.framework.EquinoxBundle.startWorker0(EquinoxBundle.java:1005)
at org.eclipse.osgi.internal.framework.EquinoxBundle$SystemBundle$EquinoxSystemModule.initWorker(EquinoxBundle.java:190)
at org.eclipse.osgi.container.SystemModule.init(SystemModule.java:99)
at org.eclipse.osgi.internal.framework.EquinoxBundle$SystemBundle.init(EquinoxBundle.java:272)
at org.eclipse.osgi.internal.framework.EquinoxBundle$SystemBundle.init(EquinoxBundle.java:257)
at org.eclipse.osgi.launch.Equinox.init(Equinox.java:171)
at org.eclipse.core.runtime.adaptor.EclipseStarter.startup(EclipseStarter.java:316)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:251)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:661)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:597)
at org.eclipse.equinox.launcher.Main.run(Main.java:1476)
"VM Thread" os_prio=2 tid=0x000000001fae8800 nid=0x32cc runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000005727800 nid=0x3264 runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000005729000 nid=0xbdf4 runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x000000000572a800 nid=0xae6c runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x000000000572d000 nid=0x588 runnable
"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x000000000572f000 nid=0xac0 runnable
"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x0000000005730800 nid=0x380 runnable
"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x0000000005733800 nid=0x216c runnable
"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x0000000005734800 nid=0xb930 runnable
"VM Periodic Task Thread" os_prio=2 tid=0x0000000021a8d000 nid=0x2dcc waiting on condition
JNI global references: 14
C:\Program Files\Java\jdk1.8.0_171\bin>
#4. JMC
JMC significa Control de misión de Java. Es una herramienta GUI de código abierto que se envía con JDK y se utiliza para recopilar y analizar datos de aplicaciones Java.
Se puede iniciar desde /compartimiento carpeta de nuestra instalación de Java. Los administradores y desarrolladores de Java utilizan la herramienta para recopilar información detallada de bajo nivel sobre los comportamientos de la aplicación y la JVM. Permite un análisis detallado y eficiente de los datos recopilados por Java. Grabador de vuelo.
Al lanzar jmc
, podemos ver la lista de procesos de Java que se están ejecutando en la máquina local. También es posible una conexión remota. En un proceso en particular, podemos hacer clic derecho y elegir Iniciar grabación de vuelo y luego verifique los volcados de hilo en el Temas .

#5. jconsole
jconsole es una herramienta de extensión de gestión de Java que se utiliza para la gestión y el seguimiento de quejas.
También tiene un conjunto de operaciones predefinidas en el agente JMX que el usuario puede realizar. Permite al usuario detectar y analizar el seguimiento de la pila de un programa en vivo. Se puede iniciar desde /compartimiento carpeta de nuestra instalación de Java.
Usando el jconsole Con la herramienta GUI podemos inspeccionar el seguimiento de la pila de cada hilo cuando lo conectamos a un proceso Java en ejecución. Luego, en la pestaña Subproceso, podemos ver el nombre de todos los subprocesos en ejecución. Para detectar un interbloqueo, podemos hacer clic en el Detectar interbloqueo en la parte inferior derecha de la ventana. Si se detecta un interbloqueo, aparecerá en una nueva pestaña. No se detectó interbloqueo será mostrado.

#6. SubprocesoMxBean
ThreadMXBean es la interfaz para la gestión del sistema de subprocesos de la máquina virtual Java perteneciente al paquete java.lang.Management. Se utiliza principalmente para detectar los subprocesos que han entrado en una situación de bloqueo y obtener detalles sobre ellos.
Podemos usar la interfaz ThreadMxBean para capturar programáticamente el volcado del hilo. getThreadMXBean()
método de ManagementFactory
se usa para obtener una instancia del ThreadMXBean
interfaz. Devuelve el número de subprocesos en vivo tanto daemon como no daemon. ManagementFactory es una clase de fábrica para obtener los beans administrados para la plataforma Java.
private static String getThreadDump (boolean lockMonitors, boolean lockSynchronizers) {
StringBuffer threadDump = new StringBuffer (System.lineSeparator ());
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean ();
for (ThreadInfo threadInfo : threadMXBean.dumpAllThreads (lockMonitors, lockSynchronizers)) {
threadDump.append (threadInfo.toString ());
}
return threadDump.toString ();
}
Manual Analysis of Thread Dumps
El análisis de volcados de subprocesos puede ser muy útil para identificar problemas en procesos multiproceso. Los problemas como los puntos muertos, la contención de bloqueos y el uso excesivo de CPU por volcados de subprocesos individuales se pueden resolver visualizando los estados de los volcados de subprocesos individuales.
El rendimiento máximo de la aplicación se puede lograr rectificando el estado de cada hilo después de analizar el volcado del hilo.
En el, digamos, un proceso está usando mucha CPU, podemos averiguar si algún subproceso está usando más la CPU. Si existe alguno de esos hilos, convertimos su número LWP en un número hexadecimal. Luego, desde el volcado del hilo, podemos encontrar el hilo con un nid igual al número hexadecimal obtenido previamente. Usando el seguimiento de la pila del hilo, podemos identificar el problema. Averigüemos el ID de proceso del hilo usando el siguiente comando.
ps -mo pid,lwp,stime,time,cpu -C java
[geekfkare@localhost ~]# ps -mo pid,lwp,stime,time,cpu -C java
PID LWP STIME TIME %CPU
26680 - Dec07 00:02:02 99.5
- 10039 Dec07 00:00:00 0.1
- 10040 Dec07 00:00:00 95.5
Echemos un vistazo a la parte de abajo del volcado de hilo. Para obtener el volcado de subprocesos para el proceso 26680, utilice jstack -l 26680
[geekfkare@localhost ~]# jstack -l 26680
2020-06-27 09:01:29
<strong>Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.221-b11 mixed mode):</strong>
"Attach Listener" #16287 daemon prio=9 os_prio=0 tid=0x00007f0814001800 nid=0x4ff2 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
.
.
.
.
.
.
.
"<strong>Reference Handler</strong>" #2 daemon prio=10 os_prio=0 tid=0x00007f085814a000 nid=0x6840 in Object.wait() [0x00007f083b2f1000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x00000006c790fbd0> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
Locked ownable synchronizers:
- None
"VM Thread" os_prio=0 tid=0x00007f0858140800 nid=0x683f runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f0858021000 nid=0x683b runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f0858022800 nid=0x683c runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f0858024800 nid=0x683d runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f0858026000 nid=0x683e runnable
"VM Periodic Task Thread" os_prio=0 tid=0x00007f08581a0000 nid=0x6847 waiting on condition
JNI global references: 1553
Ahora, veamos cuáles son las cosas que podemos explorar usando volcados de hilo. Si observamos el volcado de subprocesos, podemos ver una gran cantidad de contenido, que puede resultar abrumador. Sin embargo, si damos un paso a la vez, puede ser bastante sencillo de entender. Entendamos la primera línea
2020-06-27 09:01:29
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.221-b11 mixed mode):
Lo anterior muestra la hora en que se generó el volcado y la información sobre la JVM que se utilizó. A continuación, al final, podemos ver la lista de hilos, el primero de ellos es nuestro Controlador de referencia hilo.
Análisis de subprocesos bloqueados
Si analizamos los registros de volcado de subprocesos a continuación, podemos encontrar que ha detectado subprocesos con OBSTRUIDO estado que hace que el rendimiento de una aplicación sea muy lento. Entonces, si podemos encontrar el OBSTRUIDO hilos, podemos intentar extraer los hilos relacionados con los bloqueos que los hilos están intentando obtener. El análisis del seguimiento de la pila desde el hilo que actualmente sostiene el bloqueo puede ayudar a resolver el problema.
[geekfkare@localhost ~]# jstack -l 26680
.
.
.
.
" DB-Processor-13" daemon prio=5 tid=0x003edf98 nid=0xca waiting for monitor entry [0x000000000825f000]
java.lang.Thread.State: <strong>BLOCKED</strong> (on object monitor)
at beans.ConnectionPool.getConnection(ConnectionPool.java:102)
- waiting to lock <0xe0375410> (a beans.ConnectionPool)
at beans.cus.ServiceCnt.getTodayCount(ServiceCnt.java:111)
at beans.cus.ServiceCnt.insertCount(ServiceCnt.java:43)
"DB-Processor-14" daemon prio=5 tid=0x003edf98 nid=0xca waiting for monitor entry [0x000000000825f020]
java.lang.Thread.State: <strong>BLOCKED</strong> (on object monitor)
at beans.ConnectionPool.getConnection(ConnectionPool.java:102)
- waiting to lock <0xe0375410> (a beans.ConnectionPool)
at beans.cus.ServiceCnt.getTodayCount(ServiceCnt.java:111)
at beans.cus.ServiceCnt.insertCount(ServiceCnt.java:43)
.
.
.
.
Analizando hilo interbloqueado
Otra aplicación muy utilizada de volcados de subprocesos es la detección de puntos muertos. La detección y solución de interbloqueos puede ser mucho más sencilla si analizamos los volcados de subprocesos.
Un interbloqueo es una situación que involucra al menos dos subprocesos en la que el recurso requerido por un subproceso para continuar la ejecución está bloqueado por otro subproceso y, al mismo tiempo, el recurso requerido por el segundo subproceso está bloqueado por el primer subproceso.
Por lo tanto, ninguno de los subprocesos puede continuar la ejecución, y esto da como resultado una situación de interbloqueo y termina con la aplicación atascada. Si hay rastas, la sección final del volcado de hilo imprimirá la información sobre el punto muerto de la siguiente manera.
"Thread-0":
waiting to lock monitor 0x00000250e4982480 (object 0x00000000894465b0, a java.lang.Object),
which is held by "Thread-1"
"Thread-1":
waiting to lock monitor 0x00000250e4982380 (object 0x00000000894465a0, a java.lang.Object),
which is held by "Thread-0"
.
.
.
"Thread-0":
at DeadlockedProgram$DeadlockedRunnableImplementation.run(DeadlockedProgram.java:34)
- waiting to lock <0x00000000894465b0> (a java.lang.Object)
- locked <0x00000000894465a0> (a java.lang.Object)
at java.lang.Thread.run(java.base@10.0.1/Thread.java:844)
"Thread-1":
at DeadlockedProgram $DeadlockRunnableImplementation.run(DeadlockedProgram.java:34)
- waiting to lock <0x00000000894465a0> (a java.lang.Object)
- locked <0x00000000894465b0> (a java.lang.Object)
at java.lang.Thread.run(java.base@10.0.1/Thread.java:844)
Aquí podemos ver la información del interbloqueo en un formato bastante legible por humanos.
Aparte de esto, si sumamos todo el fragmento anterior de volcado de subprocesos juntos, entonces indica la siguiente información.
- Controlador de referencia es el nombre legible por humanos del hilo.
- #2 es la identificación única del hilo.
- demonio denota si el hilo es un hilo demonio.
- La prioridad numérica del hilo viene dada por prio= 10.
- El estado actual del hilo se denota por esperando en condición.
- Luego vemos el seguimiento de la pila, que incluye la información de bloqueo.
Thread Dumps Analyzers
Además del análisis manual, existen numerosas herramientas disponibles para analizar volcados de subprocesos, tanto en línea como fuera de línea. A continuación se muestran algunas de las herramientas enumeradas, que podemos utilizar en función de los requisitos.
Primero, exploremos las herramientas en línea.
#1. Hilo rápido
Hilo rápido es la DevOps la herramienta de análisis de volcado de hilo favorita de los ingenieros para solucionar problemas complejos de producción. Este es un analizador de volcado de subprocesos de Java en línea. Podemos cargar el volcado de subprocesos como un archivo o podemos copiar y pegar directamente el volcado de subprocesos.
Dependiendo del tamaño, analizará el volcado del hilo y mostrará la información como se muestra en la captura de pantalla.

Características
- Solucionar fallas de JVM, ralentizaciones, fugas de memoria, congelamientos, picos de CPU
- RCA instantáneo (no espere a los proveedores)
- Tablero de instrumentos intuitivo
- Soporte de API REST
- Aprendizaje automático
#2. Analizador de volcado de hilos de Spotify
La Analizador de volcado de hilos de Spotify tiene la licencia de la versión 2.0 de la licencia Apache. Es una herramienta en línea y acepta el volcado de hilo como un archivo o podemos copiar y pegar directamente el volcado de hilo. Dependiendo del tamaño, analizará el volcado del hilo y mostrará la información como se muestra en la captura de pantalla.

#3. Revisión de Jstack
Jstack.revisión analiza los volcados de subprocesos de Java desde el navegador. Esta página es solo del lado del cliente.

#4. Sitio web 24 × 7
Este del IRS es un requisito previo para detectar subprocesos defectuosos que degraden el rendimiento de la máquina virtual Java (JVM). Los problemas como los puntos muertos, la contención de bloqueos y el uso excesivo de CPU por volcados de subprocesos individuales se pueden resolver visualizando los estados de los volcados de subprocesos individuales.
El rendimiento máximo de la aplicación se puede lograr rectificando el estado de cada hilo proporcionado por la herramienta.

Ahora, exploremos las herramientas sin conexión.
Cuando se trata de crear perfiles, solo la mejor herramienta es suficientemente buena.
#1. JProfiler
JProfiler es uno de los analizadores de volcado de subprocesos más populares entre Desarrolladores de Java. La interfaz de usuario intuitiva de JProfiler lo ayuda a resolver cuellos de botella de rendimiento, identificar pérdidas de memoria y comprender los problemas de subprocesos.

JProfiler admite la creación de perfiles en las siguientes plataformas:
- Windows
- macOS
- Linux
- FreeBSD
- Solaris
- AIX
- HP-UX
A continuación se muestran algunas características que hacen de JProfiler la mejor opción para perfilar nuestras aplicaciones en la JVM.
Características
- Admite la creación de perfiles de bases de datos para JDBC, JPA y NoSQL
- También está disponible el soporte para la edición empresarial de Java
- Presenta información de alto nivel sobre llamadas RMI
- Stellar análisis de fugas de memoria
- Amplias capacidades de control de calidad
- El perfilador de subprocesos integrado está estrechamente integrado con las vistas de perfilado de la CPU.
- Soporte para plataformas, IDE y servidores de aplicaciones.
#2. IBM TMDA
IBM Thread and Monitor Dump Analyzer para Java (TMDA) es una herramienta que permite la identificación de bloqueos, interbloqueos, contención de recursos y cuellos de botella en volcados de subprocesos de Java. Es un producto de IBM, pero la herramienta TMDA se proporciona sin garantía ni soporte; sin embargo, intentan arreglar y mejorar la herramienta con el tiempo.

#3. ManageEngine
ManageEngine El administrador de aplicaciones puede ayudar a monitorear la memoria Heap y Non-Heap de JVM. Incluso podemos configurar umbrales y recibir alertas por correo electrónico, SMS, etc., y asegurarnos de que una aplicación Java esté bien ajustada.

#4. TuKit
TuKit consta de los siguientes productos denominados Kit.
- Java Profiler: generador de perfiles de baja sobrecarga con todas las funciones para las plataformas Java EE y Java SE.
- YouMonitor: supervisión del rendimiento y creación de perfiles de Jenkins, Team City, Gradle, Maven, Ant, JUnit y TestNG.
- .NET Profiler: perfilador de memoria y rendimiento fácil de usar para .NET framework.
Conclusión
Ahora ya sabe cómo los volcados de subprocesos son útiles para comprender y diagnosticar problemas en aplicaciones multiproceso. Con la debida local, con respecto a los volcados de subprocesos (su estructura, la información que contienen, etc.), podemos utilizarlos para identificar las causas de los problemas rápidamente.