Cómo analizar volcados de subprocesos
Java y subprocesos
Los servidores web utilizan entre decenas y cientos de subprocesos para manejar un gran número de usuarios simultáneos. Si varios subprocesos utilizan **** para disfrutar de los recursos, no se puede evitar la competencia por los datos entre subprocesos y, en ocasiones, pueden producirse puntos muertos.
La contención de subprocesos significa que diferentes subprocesos en un programa de red acceden a recursos disfrutados, y un subproceso espera a que otro subproceso libere el bloqueo. Por ejemplo, al iniciar sesión, el hilo de registro primero debe adquirir el bloqueo y luego acceder al recurso disfrutado.
Un punto muerto es un tipo especial de contención de subprocesos en el que dos o más subprocesos deben esperar a que otros subprocesos completen sus tareas.
La contención de subprocesos puede causar una variedad de problemas diferentes. Para analizar estos problemas, debe utilizar un volcado de subprocesos (Thread Dump) para registrar el estado real de cada subproceso.
Antecedentes de los subprocesos de Java
Sincronización de subprocesos
Se pueden ejecutar varios subprocesos al mismo tiempo para garantizar que varios subprocesos utilicen ****-enjoyed. de una manera común Recurso, la sincronización de subprocesos se utiliza para garantizar que solo un subproceso pueda acceder al recurso disfrutado a la vez.
La sincronización de subprocesos en Java se puede lograr mediante monitores. Cada objeto Java tiene un monitor, que sólo puede ser propiedad de un hilo. Cuando un subproceso desea adquirir un monitor propiedad de otro subproceso, debe ingresar a una cola de espera hasta que ese subproceso libere el monitor.
Estado del hilo
Para analizar el volcado del hilo, primero debe comprender el estado del hilo. El estado del hilo se encuentra en java.lang.Thread.State.
NUEVO: El hilo ha sido creado pero aún no se ha ejecutado
RUNNABLE: El hilo está ocupando la CPU y realizando tareas
BLOQUEADO: El hilo debe espere a que otro hilo libere el bloqueo. Obtenga el monitor.
ESPERANDO: llame a los métodos de espera, unión y estacionamiento para hacer que el hilo espere. - Espere indefinidamente
TIMED_WAITING: llame a los métodos Sleep, wait, join y park para hacer que el hilo espere; el tiempo de espera es limitado
Tipo de hilo
Los subprocesos en Java se pueden dividir en dos tipos:
1. Subproceso en segundo plano
2. Subproceso que no es en segundo plano
Cuando no se está ejecutando ningún otro subproceso que no sea en segundo plano, El hilo en segundo plano finalizará. Incluso si no crea subprocesos, las aplicaciones Java crean muchos subprocesos de forma predeterminada. La mayoría de ellos son subprocesos en segundo plano, que se utilizan principalmente para realizar tipos de tareas como gc o jmx.
Los subprocesos abiertos desde el método "static void main(String[] args)" se denominan subprocesos que no son en segundo plano. hilos Cuando se detiene, todos los demás hilos en segundo plano también se detendrán.
Obtener un volcado de subprocesos
Se introducirán tres métodos comunes. Tenga en cuenta que hay muchas otras formas de obtener volcados de subprocesos. Los volcados de subprocesos solo muestran el estado del subproceso en el momento de la medición. Por lo tanto, para ver cambios en el estado del hilo, se recomienda ejecutarlo de 5 a 10 veces cada 5 segundos.
Dapplication.home=/home1/user/java/jdk.1.6.0_24 -Xms8m
Get Thread Dump usa PID como parámetro jstack
[user@linux ~]$ jstack - f 5824
Obtener volcado de subprocesos Utilice jVisualVM para obtener el conjunto de datos del subproceso
Obtener volcado de subprocesos mediante jVisualVm
La marca a la izquierda indica el proceso actualmente en ejecución. Puede ver información del hilo en tiempo real haciendo clic en el proceso que desea ver y seleccionando la opción en tiempo real. Haga clic en el botón a la derecha del volcado de subprocesos para obtener el archivo de volcado de subprocesos
Genere el archivo en la terminal de Linux
Use el comando ps -ef para obtener el proceso Java actualmente en ejecución
[usuario@linux ~]$ ps - ef | grep java
usuario 2477 1 0 23 de diciembre 00:10:45 ...
usuario 25780 25361 0 15:02 pts/3 00:00:02 ./jstatd -J -Djava.security.policy=jstatd.all.policy -p 2999
usuario 26335 25361 0 15:49 pts/3 00:00 :00 grep java
Utilice el pid extraído como argumento para eliminar -SIGQUIT(3) y obtener un volcado del hilo.
Información del subproceso en el archivo de volcado de subprocesos
"pool-1-thread-13 " prio=6 tid=0x000000000729a000 nid=0x2fb4 ejecutable [0x0000000007f0f000] java.lang.Thread Estado: RUNNABLE en java.net.SocketInputStream.java: 158) - lt bloqueado; (inputStreamReader.java: 167) en java.io.StreamDecoder ( StreamDecoder.java:306) en sun.nio.cs.BufferedReader.fill(BufferedReader.java:136) en java.io.BufferedReader.readLine(BufferedReader.java:299) - bloqueado lt; InputStreamReader) - Bloquear.
InputStreamReader) en java.io.BufferedReader.readLine(BufferedReader.java:362)
Nombre del hilo: el nombre del hilo utilizado al generar un hilo usando la clase Java.lang.Thread, se llamará Thre- (número), pero cuando se genera un hilo usando la clase java.util.ThreadFactory, se llamará Thre- (número). Concurrencia, clase ThreadFactory, se llamará pool-(Number) -thread-(Number)
Prioridad: representa la prioridad del hilo
ID del hilo: representa la unicidad del ID del subproceso (puede obtener información útil a través del ID del subproceso, incluido el uso de la CPU o el uso de la memoria)
Estado del subproceso: representa el estado del subproceso.
Estado del hilo: indica el estado del hilo
Pila de llamadas del hilo: indica la información de la pila de la llamada del hilo
Tipo de modo de volcado del hilo
Cuando no se puede adquirir un bloqueo (bloqueo)
Cuando un hilo ocupa un bloqueo y ningún otro hilo puede adquirirlo, todo el rendimiento de la aplicación se degrada. En el siguiente ejemplo,
BLOCKED_TEST pool-1-thread-1 se está ejecutando para obtener <0x0000000780a000b0gt>, mientras BLOCKED_TEST pool-1-thread-2 y BLOCKED_TEST pool-1-thread-3 están esperando Get. la cerradura.
RUNNABLE en java.io.FileOutputStream.writeBytes(Método nativo) en java.io.FileOutputStream.write(FileOutputStream.java:282) en java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65) en java.io.BufferedOutputStream. flush(BufferedOutputStream.java:123) - bloqueado <0x0000000780a31778gt; cs.StreamEncoder.writeBytes(StreamEncoder.java:202) en sun.nio.cs.flushBuffer(StreamEncoder.java:85) - bloqueado lt;0x0000000780a040c0gt; java. io.OutputStreamWriter).OutputStreamWriter) en java.io.flushBuffer (OutputStreamWriter.java:168) en java.io.PrintStream.newLine(PrintStream.java:496) - bloqueado lt;0x0000000780a04118gt (a java.io.PrintStream.newLine; (PrintStream.java:496).io.PrintStream) en java.io.PrintStream.println(PrintStream.java:687) - bloqueado lt;0x0000000780a04118gt; (un java.io.PrintStream) en com.threaddump.ThreadBlockedState.monitorLock( ThreadBlockedState.java:44) - bloqueado lt;0x0000000780a000b0gt; (a com.nbp.threaddump.ThreadBlockedState$1.run(ThreadBlockedState.java:7) en java.util.concurrent.ThreadPoolExecutor$Worker .runTask(ThreadPoolExecutor.java:886) en java.util.concurrent.Worker.run(ThreadPoolExecutor.java:908) en java.lang.Thread.run(Thread.java:662) bloqueado propiedad
Sincronizador: - lt;0x0000000780a31758 gt; (a java.util.concurrent.locks.ReentrantLock$Non't)ReentrantLock$NonfairSync) "BLOCKED_TEST pool-1-thread-2" prio=6 tid=0x0000000007673800 nid=0x260c esperando monitor Entrada [0x0000000008ABF000] java.lang.thread.state: bloqueado (en el monitor de objetos) en com.nbp.theplatform.threaddump.threadblockedstate.monitorlock (Threadblockedstate.java: 43) - Esperando para bloquear LT; .theplatform.threaddump.ThreadBlockedState) en com.nbp.theplatform.threaddump.ThreadBlockedState$2.run(ThreadBlockedState.java:26) en java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) en java. util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) en java.lang.Thread.run(Thread.java:662) Bloqueado propio sincronizable: - lt;0x0000000780b0c6a0gt; run(java.lang.Thread.java:662)util.concurrent.locks.ReentrantLock$NonfairSync) "BLOCKED_TEST pool-1-thread-3" prio=6 tid=0x00000000074f5800 nid=0x1994 esperando la entrada del monitor [0x0000000008bbf000] java. lang.Thread.State: BLOQUEADO (en el monitor de objetos) en com.nbp.theplatform.threaddump.ThreadBlockedState .monitorLock(ThreadBlockedState.java: 42) - esperando bloquear lt; theplatform.threaddump.ThreadBlockedState$3.run(ThreadBlockedState.java:34) en java.util.concurrent.ThreadPoolExecutor$2.run(java.util.c
oncurrent.ThreadPoolExecutor$2.run(java.util.concurrent.ThreadPoolExecutor$2.run(java.util.concurrent.ThreadPoolExecutor.java:34)ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) en java.util.concurrent.ThreadPoolExecutor $Worker.run(ThreadPoolExecutor.java:908) en java.lang.Thread.run(Thread.java:662) Sincronizadores propietarios bloqueados: - lt;0x0000000780b0e1b8gt (a java.util.concurrent.locks.LOCs) util.concurrent; .locks.ReentrantLock$NonfairSync)
Cuando está en un estado de punto muerto
El subproceso A necesita adquirir el bloqueo del subproceso B para continuar ejecutando la tarea, y el subproceso B necesita adquirir el bloqueo. de hilo Un bloqueo para continuar ejecutando la tarea. En el volcado del hilo, se puede ver que el hilo DEADLOCK_TEST-1 posee el bloqueo 0x00000007d58f5e48 y está intentando adquirir el bloqueo 0x00000007d58f5e60. Además, el subproceso DEADLOCK_TEST-2 posee el bloqueo 0x00000007d58f5e60 e intenta adquirir el bloqueo 0x00000007d58f5e78. DEADLOCK_TEST-3 El subproceso posee el bloqueo 0x00000007d58f5e78 y está intentando adquirir el bloqueo 0x00000007d58f5e48. Como puede ver, cada subproceso está esperando el bloqueo del otro subproceso y este estado no cambia hasta que un subproceso abandona el bloqueo.
Demonio "DEADLOCK_TEST-1" prio=6 tid=0x000000000690f800 nid=0x1820 esperando la entrada del monitor [0x000000000805f000] java.lang.Thread Estado: BLOQUEADO (en el monitor de objetos) en com.nbp.theplatform. threaddump.ThreadDeadLockState$DeadlockThread.goMonitorDeadlock(ThreadDeadLockState.java:197) - esperando bloquear lt;0x00000007d58f5e60gt; (un com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor) en com.nbp.theplatform.threaddump.ThreadDead LockState$DeadlockTh leído. monitorOurLock (ThreadDeadLockState.java:182) - bloqueado Puede tener sincronizadores: - Ninguno "DEADLOCK_TEST-2" daemon prio=6 tid=0x0000000006858800 nid=0x17b8 esperando la entrada del monitor [0x000000000815f000] java.lang.Thread.State: BLOQUEADO (en el objeto) monitor) en com.nbp.theplatform. threaddump.ThreadDeadLockState$DeadlockThread.goMonitorDeadlock(ThreadDeadLockState.java:197) - esperando bloquear lt; 0x00000007d58f5e78gt; nbp. theplatform.threaddump.ThreadDeadLockState.goMonitor Deadlock(ThreadDeadLockState .java:197) - esperando bloquear lt; 0x00000007d58f5e78gt; (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)ThreadDeadLockState$DeadlockThread.monitorOurLo ck(ThreadDeadLockState.java:182)
- bloqueado lt;0x00000007d58f5e60gt; (a com.nbp.ThreadDeadLockState$DeadlockThread.run(ThreadDeadLockState.java:135) Sincronizadores de propiedad bloqueados: - Ninguno "DEADLOCK_TEST-3" prio=6 tid=0x0000000006859000 nid=0x25d c esperando la entrada del monitor [ 0x000000000825f000] java.lang.Thread.State: BLOQUEADO (en el monitor de objetos) en com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.goMonitorDeadlock(ThreadDeadLockState.java: 197) - esperando bloquear nbp (un archivo com.nbp.theplatform. threaddump.ThreadDeadLockState$ Monitor) en com.nbp.theplatform.threaddump .ThreadDeadLockState$DeadlockThread.run(ThreadDeadLockState.java:135) Sincronizadores propietarios bloqueados: - Ninguno
Esperando continuamente mensajes del servicio remoto p>
El hilo parece normal porque su estado siempre es EJECUTABLE, pero cuando ordenas el volcado del hilo por tiempo, puedes ver que el hilo socketReadThread siempre está leyendo el socket