usar ejemplo codigo java tomcat thread-local

java - ejemplo - jlabel netbeans



Cómo limpiar los threadlocals (6)

¿Alguien tiene un ejemplo de cómo hacer esto? o son manejados por el recolector de basura? estoy usando tomcat6


Aquí hay un código para limpiar todas las variables locales de subprocesos del subproceso actual cuando no tiene una referencia a la variable local del subproceso real. También puede generalizarlo para limpiar las variables locales de subprocesos para otros subprocesos:

private void cleanThreadLocals() { try { // Get a reference to the thread locals table of the current thread Thread thread = Thread.currentThread(); Field threadLocalsField = Thread.class.getDeclaredField("threadLocals"); threadLocalsField.setAccessible(true); Object threadLocalTable = threadLocalsField.get(thread); // Get a reference to the array holding the thread local variables inside the // ThreadLocalMap of the current thread Class threadLocalMapClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap"); Field tableField = threadLocalMapClass.getDeclaredField("table"); tableField.setAccessible(true); Object table = tableField.get(threadLocalTable); // The key to the ThreadLocalMap is a WeakReference object. The referent field of this object // is a reference to the actual ThreadLocal variable Field referentField = Reference.class.getDeclaredField("referent"); referentField.setAccessible(true); for (int i=0; i < Array.getLength(table); i++) { // Each entry in the table array of ThreadLocalMap is an Entry object // representing the thread local reference and its value Object entry = Array.get(table, i); if (entry != null) { // Get a reference to the thread local object and remove it from the table ThreadLocal threadLocal = (ThreadLocal)referentField.get(entry); threadLocal.remove(); } } } catch(Exception e) { // We will tolerate an exception here and just log it throw new IllegalStateException(e); } }


El javadoc dice esto:

"Cada subproceso contiene una referencia implícita a su copia de una variable local de subproceso, siempre que el subproceso esté activo y se pueda acceder a la instancia de ThreadLocal; después de que un subproceso desaparezca, todas sus copias de instancias locales de subproceso estarán sujetas a la recolección de basura (a menos que existan otras referencias a estas copias).

Si su aplicación o (si está hablando de hilos de solicitud) contenedor utiliza un grupo de subprocesos que significa que los subprocesos no mueren. Si es necesario, tendrá que encargarse de los locals locales usted mismo. La única manera limpia de hacerlo es llamar al método ThreadLocal.remove() .

Hay dos razones por las que es posible que desee limpiar los locales del hilo para los hilos en un grupo de subprocesos:

  • para evitar fugas de memoria (o hipotéticamente recursos), o
  • para evitar pérdidas accidentales de información de una solicitud a otra a través de locales de subprocesos.

Las pérdidas de memoria local de subprocesos normalmente no deberían ser un problema importante con los grupos de subprocesos delimitados, ya que es probable que los subprocesos locales se sobrescriban con el tiempo; es decir, cuando el hilo se reutiliza. Sin embargo, si comete el error de crear una nueva instancia de ThreadLocal una y otra vez (en lugar de usar una variable static para contener una instancia singleton), los valores locales de la secuencia no se sobrescribirán y se acumularán en el mapa de threadlocals cada thread. Esto podría provocar una fuga seria.

Suponiendo que está hablando de localizaciones de subprocesos que se crean / utilizan durante el procesamiento de una aplicación HTTP por una aplicación web, una forma de evitar las filtraciones locales de subprocesos es registrar ServletRequestListener con ServletContext su aplicación web e implementar el método ServletRequestListener la escucha para limpiar el subproceso locales para el hilo actual.

Tenga en cuenta que en este contexto también debe considerar la posibilidad de que se filtre información de una solicitud a otra.


La JVM limpiará automáticamente todos los objetos sin referencia que están dentro del objeto ThreadLocal.

Otra forma de limpiar esos objetos (por ejemplo, estos objetos podrían ser todos los objetos inseguros de hilo existentes) es ponerlos dentro de una clase Object Holder, que básicamente lo mantiene y puede anular el método finalize para limpiar el objeto que reside dentro de ella. De nuevo, depende del Garbage Collector y sus políticas, cuando invocaría el método de finalize .

Aquí hay una muestra de código:

public class MyObjectHolder { private MyObject myObject; public MyObjectHolder(MyObject myObj) { myObject = myObj; } public MyObject getMyObject() { return myObject; } protected void finalize() throws Throwable { myObject.cleanItUp(); } } public class SomeOtherClass { static ThreadLocal<MyObjectHolder> threadLocal = new ThreadLocal<MyObjectHolder>(); . . . }


Leyendo nuevamente la documentación de Javadoc cuidadosamente:

''Cada hilo contiene una referencia implícita a su copia de una variable local del hilo, siempre que el hilo esté vivo y se pueda acceder a la instancia de ThreadLocal; después de que un hilo desaparece, todas sus copias de instancias locales de subprocesos están sujetas a la recolección de elementos no utilizados (a menos que existan otras referencias a estas copias). ''

No hay necesidad de limpiar nada, existe una condición ''AND'' para que la fuga sobreviva. Así que incluso en un contenedor web donde el hilo sobreviva a la aplicación, siempre que la clase de webapp esté descargada (solo la referencia de beeing en una clase estática cargada en el cargador de clase padre evitaría esto y esto no tiene nada que ver con ThreadLocal pero problemas generales con recipientes compartidos con datos estáticos), entonces el segundo tramo de la condición AND ya no se cumple, por lo que la copia local del subproceso es elegible para la recolección de elementos no utilizados.

El subproceso local no puede ser la causa de pérdidas de memoria, siempre que la implementación cumpla con la documentación.


Me gustaría contribuir con mi respuesta a esta pregunta a pesar de que es antigua. Me había visto afectado por el mismo problema (el hilo local no se eliminaba del hilo de solicitud), e incluso me había acostumbrado a reiniciar el servidor cada vez que se quedaba sin memoria (¡lo cual es una mierda!).

En el contexto de una aplicación web java que está configurada en modo dev (porque el servidor está configurado para rebotar cada vez que detecta un cambio en el código, y posiblemente también se ejecuta en modo de depuración), aprendí rápidamente que los hilos de ruta pueden ser impresionantes y en algún momento ser un dolor. Estaba usando una Invocación threadlocal para cada solicitud. Dentro de la Invocación. A veces también uso gson para generar mi respuesta. Me gustaría envolver la Invocación dentro de un bloque ''try'' en el filtro, y destruirlo dentro de un bloque ''finally''.

Lo que observé (no tengo métricas para respaldar esto por ahora) es que si hiciera cambios a varios archivos y el servidor rebotara constantemente entre mis cambios, me impacientaría y reiniciaría el servidor (tomcat para ser precisos) del IDE. Lo más probable es que termine con una excepción de ''Falta de memoria''.

Cómo supero esto fue incluir una implementación de ServletRequestListener en mi aplicación, y mi problema desapareció. Creo que lo que sucedía era que, en medio de una solicitud, si el servidor rebotaba varias veces, mis threadlocals no se estaban aclarando (incluido el gson), así que recibí esta advertencia sobre los hilos y dos o tres advertencias más adelante. el servidor se bloquee. Con ServletResponseListener cerrando explícitamente mis threadlocals, el problema gson desapareció.

Espero que esto tenga sentido y te dé una idea de cómo superar los problemas de threadlocal. Siempre ciérrelos alrededor de su punto de uso. En ServletRequestListener, pruebe cada contenedor local de thread, y si todavía tiene una referencia válida a algún objeto, destrúyalo en ese punto.

También debo señalar que es un hábito envolver un threadlocal como una variable estática dentro de una clase. De esta forma, se le puede garantizar que al destruirlo en ServeltRequestListener, no tendrá que preocuparse por otras instancias de la misma clase dando vueltas.


No hay forma de limpiar los valores de ThreadLocal , excepto desde el hilo que los puso allí en primer lugar (o cuando el hilo se recolecta basura, no el caso con los hilos de trabajo). Esto significa que debe tener cuidado de limpiar su ThreadLocal cuando se finaliza una solicitud de servlet (o antes de transferir AsyncContext a otro hilo en el Servlet 3), porque después de ese punto es posible que nunca tenga la oportunidad de ingresar ese hilo de trabajo específico, y por lo tanto, perderá memoria en situaciones en las que su aplicación web no se despliegue mientras el servidor no se reinicia.

Un buen lugar para hacer tal limpieza es ServletRequestListener.requestDestroyed() .

Si usa Spring, todo el cableado necesario ya está en su lugar, simplemente puede colocar cosas en su alcance de solicitud sin preocuparse por limpiarlas (eso sucede automáticamente):

RequestContextHolder.getRequestAttributes().setAttribute("myAttr", myAttr, RequestAttributes.SCOPE_REQUEST); . . . RequestContextHolder.getRequestAttributes().getAttribute("myAttr", RequestAttributes.SCOPE_REQUEST);