java - programacion - ¿Cómo saber qué hilo sostiene el monitor?
lectores en java (1)
Mi aplicación está utilizando Gson 2.2
para convertir POJOs
a JSON
. Cuando estaba haciendo una prueba de carga, me topé con muchos hilos bloqueados en el constructor de Gson
:
"http-apr-28201-exec-28" #370 daemon prio=5 os_prio=0 tid=0x0000000001ee7800 nid=0x62cb waiting for monitor entry [0x00007fe64df9a000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.google.gson.Gson.<init>(Gson.java:200)
at com.google.gson.Gson.<init>(Gson.java:179)
El volcado de hilo NO muestra ningún hilo que [0x00007fe64df9a000] monitor
. ¿Cómo puedo saber quién lo sostiene?
Gson
código de Gson
en la línea 200 parece bastante inocente:
// built-in type adapters that cannot be overridden
factories.add(TypeAdapters.STRING_FACTORY);
factories.add(TypeAdapters.INTEGER_FACTORY);
Estoy usando JRE 1.8.0_91
en Linux
tl; dr Creo que se está ejecutando en el comportamiento relacionado con GC, donde los subprocesos se están poniendo en estado de espera para permitir la recolección de basura.
No tengo toda la verdad, pero espero proporcionar algunas ideas.
Lo primero que debe darse cuenta es que el número entre paréntesis, [0x00007fe64df9a000]
, no es la dirección de un monitor. El número entre paréntesis se puede ver para todos los subprocesos en un volcado, incluso los subprocesos que están en estado de ejecución. El número tampoco cambia. Ejemplo de mi prueba de volcado:
main" #1 prio=5 os_prio=0 tid=0x00007fe27c009000 nid=0x27e5c runnable [0x00007fe283bc2000]
java.lang.Thread.State: RUNNABLE
at Foo.main(Foo.java:12)
No estoy seguro de qué significa el número, pero esta página sugiere que es:
... el puntero a la estructura de subproceso interno de Java VM. Por lo general, no tiene ningún interés a menos que esté depurando una máquina virtual Java en vivo o un archivo central.
Aunque el formato de la traza explicada es un poco diferente, no estoy seguro de que sea correcto.
La forma en que se ve un volcado cuando se muestra la dirección del monitor real:
"qtp48612937-70" #70 prio=5 os_prio=0 tid=0x00007fbb845b4800 nid=0x133c waiting for monitor entry [0x00007fbad69e8000]
java.lang.Thread.State: BLOCKED (on object monitor)
at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:233)
- waiting to lock <0x00000005b8d68e90> (a java.lang.Object)
Observe la línea de waiting to lock
en la traza y que la dirección del monitor es diferente del número entre paréntesis.
El hecho de que no podamos ver la dirección del monitor involucrado indica que el monitor existe solo en código nativo.
En segundo lugar , el código Gson involucrado no contiene ninguna sincronización. El código simplemente agrega un elemento a un ArrayList
(suponiendo que no se haya realizado ninguna manipulación de bytecode y que no se haga nada sospechoso a un nivel bajo). Es decir, no tendría sentido ver el hilo esperando un monitor de sincronización estándar en esta llamada.
Encontré some indications que los subprocesos se pueden mostrar como esperando una entrada de monitor cuando hay mucho GC en marcha.
Escribí un programa de prueba simple para intentar reproducirlo simplemente agregando muchos elementos a una lista de arreglos:
List<String> l = new ArrayList<>();
while (true) {
for (int i = 0; i < 100_100; i++) {
l.add("" + i);
}
l = new ArrayList<>();
}
Luego tomé volcados de hilo de este programa. Ocasionalmente me encontré con el siguiente rastro:
"main" #1 prio=5 os_prio=0 tid=0x00007f35a8009000 nid=0x12448 waiting on condition [0x00007f35ac335000]
java.lang.Thread.State: RUNNABLE
at Foo.main(Foo.java:10) <--- Line of l.add()
Si bien no es idéntico a la traza del OP, es interesante tener una waiting on condition
subproceso waiting on condition
que no se requiere sincronización. Lo experimenté con más frecuencia con un montón más pequeño, lo que indica que podría estar relacionado con GC.
Otra posibilidad podría ser que el código que contiene la sincronización se haya compilado JIT y que le impida ver la dirección real del monitor. Sin embargo, creo que es menos probable ya que lo experimentas en ArrayList.add
. Si ese es el caso, no conozco ninguna manera de averiguar el titular real del monitor.