2011-08-15 21 views
18

Tengo dificultades para entender el volcado de hilo que obtuve de jstack para una aplicación web Spring MVC que se ejecuta en Tomcat 6 (java 1.6.0_22, Linux) .Volcado de hilo Java: BLOQUEADO hilo sin "esperar para bloquear ..."

Veo hilos de bloqueo (que hacen que otros hilos esperen) que se bloquean ellos mismos, sin embargo, el volcado de hilo no me dice por qué o para qué monitor están esperando.

Ejemplo:

"TP-Processor75" daemon prio=10 tid=0x00007f3e88448800 nid=0x56f5 waiting for monitor entry [0x00000000472bc000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
     at java.lang.Class.initAnnotationsIfNecessary(Class.java:3067) 
     - locked <0x00007f3e9a0b3830> (a java.lang.Class for org.catapultframework.resource.ResourceObject) 
     at java.lang.Class.getAnnotation(Class.java:3029) 
     ... 

es decir Me falta la línea "esperando para bloquear ..." en el seguimiento de la pila. Aparentemente, el hilo bloquea un objeto Class, pero no veo por qué el hilo está bloqueado.

El subproceso de subprocesos no contiene ningún indicio de interbloqueos.

¿Qué puedo hacer para identificar el monitor de bloqueo?

Gracias, Oliver

+0

¿Ve alguna otra entrada para referencia 0x00000000472bc000? –

+0

No, no en el mismo vertedero. 0x00000000472bc000 identifica el hilo "TP-Processor75", ¿así que esperas múltiples menciones del mismo hilo dentro del volcado? – Oliver

+0

Bien 0x00000000472bc000 indica el monitor que el subproceso está esperando para entrar. Ese es otro subproceso que ha entrado en la referencia de monitor 0x00000000472bc000 y el TP-Processor75 está esperando el subproceso que se está reteniendo actualmente para liberar 0x00000000472bc000 –

Respuesta

10

Al parecer, la situación en la que se observó este tipo de hilos bloqueados estaban relacionados con el consumo de memoria pesada y, por tanto, la colección masiva de basura.

Esta pregunta Java blocking issue: Why would JVM block threads in many different classes/methods? describe una situación similar, así que creo que estos hilos simplemente fueron bloqueados por el recolector de basura.

(De todos modos, después de resolver el problema de memoria este problema con las roscas de bloqueo se había ido.)

2

tuve un problema similar hace un momento utilizando un applet en Google Chrome.

En resumen:

  • Los hilos bloqueados pueden ser bloqueados cuando el VM necesita cargar una clase.
  • Cuando el proceso de cargar la clase en sí está bloqueado por algo, se puede congelar toda la aplicación.

en detalle:

que tenían el siguiente escenario:

  1. estoy usando un applet en Chrome con código base = carpeta a la clase-archivos individuales (sin frasco)
  2. El sitio web pasa los eventos de foco al applet usando LiveConnect
  3. Las llamadas JS entrantes están usando un Executor con new Runnable() ... para de conecte las llamadas para reducir los tiempos de espera y, por lo tanto, se bloquea en JS.
  4. ¡Ahí es donde ocurrió el problema!

Explicación:

  • El new Runnable() es una clase interna annonymous que no se ha cargado antes de que ocurriera la llamada JS.
  • La llamada JS desencadena la carga de clase.
  • Pero ahora el cargador de clases está bloqueado porque necesita hablar con el navegador (supongo) a través de la misma cola o mecanismo que está procesando la llamada entrante JS.

Aquí está bloqueado el hilo que está tratando de cargar la clase:

"Thread-20" daemon prio=4 tid=0x052e8400 nid=0x4608 in Object.wait() [0x0975d000] 
    java.lang.Thread.State: WAITING (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    at sun.plugin2.message.Queue.waitForMessage(Unknown Source) 
    - locked <0x29fbc5d8> (a sun.plugin2.message.Queue) 
    at sun.plugin2.message.Pipe$2.run(Unknown Source) 
    at com.sun.deploy.util.Waiter$1.wait(Unknown Source) 
    at com.sun.deploy.util.Waiter.runAndWait(Unknown Source) 
    at sun.plugin2.message.Pipe.receive(Unknown Source) 
    at sun.plugin2.main.client.MessagePassingExecutionContext.doCookieOp(Unknown Source) 
    at sun.plugin2.main.client.MessagePassingExecutionContext.getCookie(Unknown Source) 
    at sun.plugin2.main.client.PluginCookieSelector.getCookieFromBrowser(Unknown Source) 
    at com.sun.deploy.net.cookie.DeployCookieSelector.getCookieInfo(Unknown Source) 
    at com.sun.deploy.net.cookie.DeployCookieSelector.get(Unknown Source) 
    - locked <0x298da868> (a sun.plugin2.main.client.PluginCookieSelector) 
    at sun.net.www.protocol.http.HttpURLConnection.setCookieHeader(Unknown Source) 
    at sun.net.www.protocol.http.HttpURLConnection.writeRequests(Unknown Source) 
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source) 
    - locked <0x2457cdc0> (a sun.net.www.protocol.http.HttpURLConnection) 
    at com.sun.deploy.net.HttpUtils.followRedirects(Unknown Source) 
    at com.sun.deploy.net.BasicHttpRequest.doRequest(Unknown Source) 
    at com.sun.deploy.net.BasicHttpRequest.doGetRequestEX(Unknown Source) 
    at com.sun.deploy.cache.ResourceProviderImpl.checkUpdateAvailable(Unknown Source) 
    at com.sun.deploy.cache.ResourceProviderImpl.isUpdateAvailable(Unknown Source) 
    at com.sun.deploy.cache.DeployCacheHandler.get(Unknown Source) 
    - locked <0x245727a0> (a java.lang.Object) 
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source) 
    at sun.net.www.protocol.http.HttpURLConnection.connect(Unknown Source) 
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source) 
    - locked <0x24572020> (a sun.net.www.protocol.http.HttpURLConnection) 
    at java.net.HttpURLConnection.getResponseCode(Unknown Source) 
    at sun.plugin2.applet.Applet2ClassLoader.getBytes(Unknown Source) 
    at sun.plugin2.applet.Applet2ClassLoader.access$000(Unknown Source) 
    at sun.plugin2.applet.Applet2ClassLoader$1.run(Unknown Source) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at sun.plugin2.applet.Applet2ClassLoader.findClass(Unknown Source) 
    at sun.plugin2.applet.Plugin2ClassLoader.loadClass0(Unknown Source) 
    at sun.plugin2.applet.Plugin2ClassLoader.loadClass(Unknown Source) 
    - locked <0x299726b8> (a sun.plugin2.applet.Applet2ClassLoader) 
    at sun.plugin2.applet.Plugin2ClassLoader.loadClass(Unknown Source) 
    - locked <0x299726b8> (a sun.plugin2.applet.Applet2ClassLoader) 
    at java.lang.ClassLoader.loadClass(Unknown Source) 

Como se puede ver que está esperando un mensaje ->waitForMessage().

Al mismo tiempo existe nuestra llamada entrante JS siendo bloqueado aquí:

"Applet 1 LiveConnect Worker Thread" prio=4 tid=0x05231800 nid=0x1278 waiting for monitor entry [0x0770e000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
    at MyClass.myMethod(MyClass.java:23) 
    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 sun.plugin.javascript.Trampoline.invoke(Unknown Source) 
    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 sun.plugin.javascript.JSClassLoader.invoke(Unknown Source) 
    at sun.plugin2.liveconnect.JavaClass$MethodInfo.invoke(Unknown Source) 
    at sun.plugin2.liveconnect.JavaClass$MemberBundle.invoke(Unknown Source) 
    at sun.plugin2.liveconnect.JavaClass.invoke0(Unknown Source) 
    at sun.plugin2.liveconnect.JavaClass.invoke(Unknown Source) 
    at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo$DefaultInvocationDelegate.invoke(Unknown Source) 
    at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo$3.run(Unknown Source) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo.doObjectOp(Unknown Source) 
    at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo$LiveConnectWorker.run(Unknown Source) 
    at java.lang.Thread.run(Unknown Source) 

otros hilos adicionales fueron bloqueados de la misma manera. Supongo que todas las solicitudes de carga de clase subsiguientes fueron bloqueadas por el primer hilo bloqueado de carga de clases.

Como mencioné antes, supongo que el proceso de carga de clases está bloqueado por la llamada pendiente de JS, que por sí misma está bloqueada por la clase faltante que se va a cargar.

Soluciones:

  1. gatillo cargar todas las clases relevantes en el constructor del applet antes de que se puedan hacer llamadas de JS.
  2. Podría ser útil si los archivos de clase no se cargan individualmente, sino a partir de un archivo jar. La teoría detrás de esto es: El cargador de clases no necesita hablar con el navegador para cargar las clases desde el archivo jar (que sería
  3. en combinación con 1 .: utilizar una clase dinámica Proxy para ajustar todas las llamadas entrantes JS y ejecutar de forma independiente en un Executor

Mi aplicación para # 3:

public class MyClass implements JsCallInterface 
{ 

    private final JsCallInterface jsProxy; 

    private final static interface JsCallInterface 
    { 
     public void myMethod1Intern(String param1, String param2); 
    } 

    private final class JsCallRunnable implements Runnable 
    { 

     private final Method method; 
     private final Object[] args; 

     private JsCallRunnable(Method method, Object[] args) 
     { 
      this.method = method; 
      this.args = args; 
     } 

     public void run() 
     { 
      try 
      { 
       method.invoke(MyClass.this, args); 
      } 
      catch (Exception e) 
      { 
       e.printStackTrace(); 
      } 
     } 
    } 

    public MyClass() 
    { 
     MyUtilsClass.class.getName(); // load class 
     JsCallRunnable.class.getName(); // load class 
     InvocationHandler jsCallHandler = new InvocationHandler() 
     { 

      public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable 
      { 
       MyUtilsClass.executeInExecutor(new JsCallRunnable(method, args)); 
       return null; 
      } 

     }; 
     jsProxy = (JsCallInterface) Proxy.newProxyInstance(MyClass.class.getClassLoader(), new Class<?>[] { JsCallInterface.class }, jsCallHandler); 
    } 

    public void myMethod1(String param1, String param2) 
    { 
     jsProxy.myMethod1Intern(param1, param2); 
     // needs to be named differently than the external method or else the proxy will call this method recursively 
     // alternatively the target-class in "method.invoke(MyClass.this, args);" could be a different instance of JsCallInterface 
    } 

    public void myMethod1Intern(String param1, String param2) 
    { 
     // do actual work here 
    } 
} 
0

Esto es un error cosmético en Oracle HotSpot JVM - en su seguimiento de la pila donde se ve - locked <0x00007f3e9a0b3830> que en realidad debería decir - waiting to lock <0x00007f3e9a0b3830>.

Ver this bug para más detalles.

3

Compruebe si el hilo del finalizador está bloqueado o en espera.

Durante un barrido de GC, el GC "detendrá al mundo" para realizar su limpieza. La definición de "mundo" depende del recolector de basura que se usa y el contexto. Puede ser un pequeño grupo de hilos o todos ellos. Antes de recolectar basura oficialmente, GC invocará el finalize() del objeto.

Si se encuentra en una situación no deseada en la que está implementando métodos de finalización, el código de finalización puede estar impidiendo que finalice y el 'mundo' se detiene.

Esto es más obvio cuando se ven muchos hilos bloqueados permanentemente por una fuerza mágica desconocida: busca el código donde ocurre el bloqueo y no tendrá sentido; no hay ningún código de bloqueo en ninguna parte cerca de él y los volcados no divulgarán qué monitor está esperando porque no hay uno. El GC ha detenido los hilos.

Cuestiones relacionadas