2010-07-13 15 views
7

He notado algo muy extraño ayer. Parece que dos hilos entran en dos bloques sincronizados que bloquean el mismo objeto al mismo tiempo.¡la sección sincronizada no bloquea!

La clase (MyClass) que contiene el código en cuestión es similar a esto:

private static int[] myLock = new int[0]; 

protected static int methodA(final long handle, final byte[] sort) { 
    synchronized (myLock) { 
     return xsMethodA(handle, sort); 
    } 
} 

protected static int methodB(final long handle) { 
    synchronized (myLock) { 
     return xsMethodB(handle); 
    } 
} 

he creado un vertedero de hilo de mi aplicación que se ejecuta la clase anterior y estaba muy sorprendido cuando vi esto:

"http-8080-136" daemon prio=10 tid=0x00000000447df000 nid=0x70ed waiting for monitor entry [0x00007fd862aea000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
    at com.MyClass.methodA(MyClass.java:750) 
    - locked <0x00007fd8a6b8c790> (a [I) 
    at com.SomeOtherClass.otherMethod(SomeOtherClass.java:226) 
    ... 

"http-8080-111" daemon prio=10 tid=0x00007fd87d1a0000 nid=0x70c8 waiting for monitor entry [0x00007fd86e15f000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
    at com.MyClass.methodB(MyClass.java:991) 
    - locked <0x00007fd8a6b8c790> (a [I) 
    at com.SomeOtherClass.yetAnotherMethod(SomeOtherClass.java:3231) 
    ... 

(I cambiaron los nombres de clase y método para el caso de la simplicidad, por lo que no se confundan con los nombres tontos.)

parece que thr ead http-8080-136 y http-8080-111 han adquirido el candado en myLock. Es el mismo objeto que la dirección del objeto es la misma: 0x00007fd8a6b8c790. El tiempo de ejecución de Java Especificación dice esto acerca de la palabra clave synchronized:

Una declaración sincronizado adquiere un bloqueo de exclusión mutua (§17.1) en nombre del subproceso en ejecución, ejecuta un bloque, a continuación, libera el bloqueo. Mientras que el hilo de ejecución posee el candado, ningún otro hilo puede adquirir el candado. [The Java Language Specification, 14.19]

Entonces, ¿cómo es esto posible?

Hay otros 44 hilos en el volcado de hilo "en espera" de la cerradura. Así es como parece que un hilo está esperando:

"http-8080-146" daemon prio=10 tid=0x00007fd786dab000 nid=0x184b waiting for monitor entry [0x00007fd8393b6000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
    at com.MyClass.methodC(MyClass.java:750) 
    - waiting to lock <0x00007fd8a6b8c790> (a [I) 
    at com.SomeOtherClass.yetAnoterMethod2(SomeOtherClass.java:226) 

Respuesta

4

le he pedido a la misma pregunta en la lista de correo hotspot-dev y recibió una respuesta muy Goot de Christopher Phillips:


Hola Eduard

Creo que es el vertedero de hilo que es engañoso .

Si realmente piensas que los 2 están en la cerradura al mismo tiempo, probablemente deberías obtener un gcore (que es externamente consistente).

El estado que se ve "en espera de entrada de monitor" es en realidad MONITOR_WAIT que puede representar el siguiente código antes de la adquisición real de una cerradura caliente: (también ver OSThreadContendState en osThread.hpp) llamado desde: src/share/vm/runtime/synchronizer.CPP

3413  OSThreadContendState osts(Self->osthread()); 
3414  ThreadBlockInVM tbivm(jt); 
3415 
3416  Self->set_current_pending_monitor(this); 
3417 
3418  // TODO-FIXME: change the following for(;;) loop to straight-line code. 
3419  for (;;) { 
3420  jt->set_suspend_equivalent(); 
3421  // cleared by handle_special_suspend_equivalent_condition() 
3422  // or java_suspend_self() 
3423 
3424  EnterI (THREAD) ; 
3425 
3426  if (!ExitSuspendEquivalent(jt)) break ; 
3427 
3428  // 
3429  // We have acquired the contended monitor, but while we were 
3430  // waiting another thread suspended us. We don't want to enter 
3431  // the monitor while suspended because that would surprise the 
3432  // thread that suspended us. 

Chris

1

¿Cómo se tomó el volcado de hilo? Si los hilos no se pausaron, la propiedad del candado podría haber cambiado entre arrojar un hilo y el siguiente.

+0

Mediante el envío de la señal QUIT para el proceso. No sé cómo actúa Sun VM durante el volcado de la hebra. Pero supongo que el proceso se detiene. De lo contrario, obtendría un volcado de hilos incoherente. –

+0

Sé que para IBM JVM esto no es necesariamente cierto, no estoy seguro acerca de SUN, sin embargo, definitivamente algo a tener en cuenta. –

+0

Este sitio reclama que todos los hilos están en pausa: http://expertodev.wordpress.com/2009/05/30/how-to-take-java-thread-dump/ –

0

Creo que la información relevante es: "esperando la entrada del monitor", que es la misma para ambos hilos. Como ambos hilos (en el volcado de hilo) están marcados como hilos deamon, supongo que también debe haber un hilo principal ejecutándose al mismo tiempo. ¿Es posible que el hilo principal sea el propietario actual del monitor que bloquea los otros dos hilos?

+0

No, el hilo principal no hace nada. Incluso si el hilo principal mantendría el bloqueo, la especificación no distingue entre hilos principales y deamon. Solo un hilo tiene permiso para tener un candado. –

+0

Acepto, solo se permite que un subproceso obtenga el bloqueo e ingrese a la sección crítica (de acuerdo con la especificación). Ambos hilos deamon están * esperando * por el bloqueo, como se indica en el volcado de hilo. ¿Estás seguro de que no hay otro hilo que sujete el candado actualmente? – Javaguru

+0

Los dos hilos http-8080-136 y http-8080-111 mantienen el bloqueo. Hay otros 44 hilos en el volcado de hilo "esperando" el bloqueo. –

0

No han adquirido el bloqueo, de lo contrario, vería xsMethodA o xsMethodB en un stacktrace.

+0

Entonces, ¿por qué hay una diferencia entre los hilos http-8080-111 y http-8080-146? –

+0

Y: ThreadDumpAnalyzer enumera ambos hilos (http-8080-136, http-8080-111) como "bloqueado por". –

+0

Quiero decir que el título "sincronizado no bloquea" es incorrecto. ¿Quizás te refieres a "bloques de bloques sincronizados cuando nadie tiene el candado"? –

Cuestiones relacionadas