usar servlet que example ejemplo contenedor java multithreading tomcat servlets spring-mvc

java - que - ¿Cuál es la forma recomendada para generar hilos de un servlet en Tomcat



tomcat que es (6)

Esta pregunta ya tiene una respuesta aquí:

¡Probablemente una repetición! Estoy usando Tomcat como mi servidor y quiero saber cuál es la mejor manera de engendrar hilos en el servlet con resultados deterministas. Estoy ejecutando algunas actualizaciones de larga ejecución de una acción servlet y me gustaría que la solicitud se complete y las actualizaciones se realicen en segundo plano. En lugar de agregar un middleware de mensajería como RabbitMQ, pensé que podría engendrar un hilo que podría ejecutarse en segundo plano y terminar en su propio tiempo. Leí en otros hilos SO que el servidor termina hilos generados por el servidor para que pueda gestionar bien los recursos.

¿Hay una manera recomendada de engendrar hilos, trabajos de fondo cuando se utiliza Tomcat? También uso Spring MVC para la aplicación.


Desde la primavera 3, puedes usar las anotaciones @Async:

@Service public class smg { ... @Async public getCounter() {...} }

con <context:component-scan base-package="ch/test/mytest"> y <task:annotation-driven/> en el archivo de contexto

Por favor, consulte este tutorial: http://spring.io/blog/2010/01/05/task-scheduling-simplifications-in-spring-3-0/

Funciona muy bien para mí en Tomcat7 y no es necesario administrar un grupo de subprocesos.


Estrictamente hablando, no está permitido engendrar hilos de acuerdo con la especificación Java EE. También consideraría la posibilidad de un ataque de denegación de servicio (deliberado o no) si entran varias solicitudes a la vez.

Una solución de middleware definitivamente sería más robusta y compatible con los estándares.


Quizás podría usar una implementación CommonJ WorkManager (JSR 237) como Foo-CommonJ :

CommonJ - JSR 237 Timer y WorkManager

Foo-CommonJ es una implementación de JSR 237 Timer y WorkManager. Está diseñado para ser utilizado en contenedores que no vienen con su propia implementación, principalmente contenedores de servlets simples como Tomcat . También se puede usar en servidores de aplicaciones Java EE totalmente volados que no tienen una API de WorkManager o tienen una API no estándar como JBoss.

¿Por qué usar WorkManagers?

El caso de uso común es que un Servlet o JSP necesita agregar datos de múltiples fuentes y mostrarlos en una página. Hacer su propio enhebrado de un entorno administrado como un contenedor J2EE es inapropiado y nunca debe hacerse en el código de nivel de la aplicación . En este caso, la API de WorkManager se puede usar para recuperar los datos en paralelo.

Instalar / Desplegar CommonJ

La implementación de recursos JNDI depende del proveedor. Esta implementación viene con una clase Factory que implementa la interfaz javax.naming.spi.ObjectFactory con la que se puede implementar fácilmente en los contenedores más populares. También está disponible como un servicio de JBoss. Más...

Actualización: solo para aclarar, esto es lo que las Utilidades de concurrencia para Java EE Preview (parece que este es el sucesor de JSR-236 y JSR-237) escribe sobre hilos no administrados:

2.1 Subprocesos gestionados por contenedor y no gestionados

Los servidores de aplicaciones Java EE requieren administración de recursos para centralizar la administración y proteger los componentes de aplicaciones de consumir recursos innecesarios. Esto se puede lograr mediante la combinación de recursos y la administración del ciclo de vida de un recurso. El uso de utilidades de simultaneidad de Java SE como java.util.concurrency API, java.lang.Thread y java.util.Timer en un componente de aplicación de servidor como un servlet o EJB son problemáticos ya que el contenedor y el servidor no tienen conocimiento de estos recursos. .

Al extender la API java.util.concurrent , los servidores de aplicaciones y los contenedores Java EE pueden tomar conciencia de los recursos que se utilizan y proporcionar el contexto de ejecución adecuado para las operaciones asíncronas para ejecutar .

Esto se logra principalmente al proporcionar versiones administradas de las interfaces java.util.concurrent.ExecutorService predominantes.

Entonces, nada nuevo de IMO, el "viejo" problema es el mismo, el subproceso no administrado aún son hilos no gestionados:

  • Son desconocidos para el servidor de aplicaciones y no tienen acceso a la información contextual de Java EE.
  • Pueden usar recursos en la parte posterior del servidor de aplicaciones, y sin la capacidad de administración para controlar su número y el uso de recursos, esto puede afectar la capacidad del servidor de aplicaciones para recuperar recursos de fallas o apagarlos correctamente.

Referencias


Sé que es una vieja pregunta, pero la gente sigue preguntándolo, tratando de hacer este tipo de cosas (generando hilos explícitamente mientras procesas una solicitud de servlet) todo el tiempo ... Es un enfoque muy defectuoso, por más de una razón. Simplemente decir que los contenedores Java EE fruncen el ceño ante tal práctica no es suficiente, aunque generalmente es cierto ...

Lo más importante es que nunca se puede predecir cuántas solicitudes simultáneas recibirá el servlet en un momento determinado. Una aplicación web, un servlet, por definición, debe ser capaz de procesar múltiples solicitudes en el punto final dado a la vez. Si está programando, solicita lógica de procesamiento para lanzar explícitamente un cierto número de subprocesos concurrentes, se arriesga a enfrentar una situación casi inevitable de quedarse sin hilos disponibles y ahogando su aplicación. Su ejecutor de tareas siempre está configurado para trabajar con un grupo de subprocesos que está limitado a un tamaño finito razonable. Muy a menudo, no es más grande que 10-20 (no quiere demasiados hilos ejecutar su lógica, dependiendo de la naturaleza de la tarea, los recursos que compiten, la cantidad de procesadores en su servidor, etc.) Digamos , su controlador de solicitud (por ejemplo, el método de controlador MVC) invoca uno o más métodos @ Async-annotated (en cuyo caso Spring abstrae al ejecutor de tareas y le facilita las cosas) o utiliza el ejecutor de tareas explícitamente. A medida que se ejecuta el código, comienza a capturar los hilos disponibles del grupo. Eso está bien si siempre está procesando una solicitud a la vez sin solicitudes de seguimiento inmediatas. (En ese caso, probablemente esté tratando de usar la tecnología incorrecta para resolver su problema.) Sin embargo, si se trata de una aplicación web que está expuesta a clientes arbitrarios (o incluso conocidos) que pueden estar presionando al punto final con las solicitudes, lo hará agote rápidamente el grupo de subprocesos, y las solicitudes comenzarán a acumularse, esperando que los hilos estén disponibles. Por esa sola razón, debe darse cuenta de que puede estar en un camino equivocado, si está considerando tal diseño.

Una mejor solución puede ser organizar los datos para que se procesen de forma asíncrona (que podría ser una cola, o cualquier otro tipo de almacén de datos temporal / provisional) y devolver la respuesta. Haga que una aplicación externa e independiente o incluso varias instancias de la misma (desplegadas fuera de su contenedor web) sondeen los puntos finales intermedios y procesen los datos en segundo plano, posiblemente usando un número finito de hilos concurrentes. No solo esa solución le dará la ventaja del procesamiento simultáneo / asíncrono, sino que también se escalará porque podrá ejecutar tantas instancias de dicho sondeador como necesite, y se pueden distribuir apuntando al punto final intermedio. HTH


Spring admite tareas asíncronas (en su caso de larga ejecución) a través de la programación de primavera. En lugar de usar hilos directos de Java, sugiero usarlo con Quartz.

Recursos:


Su apuesta más segura es utilizar un grupo de hilos de amplia aplicación con una cantidad máxima de hilos, de modo que las tareas se pondrán en cola cada vez que sea necesario. El ExecutorService es muy útil en esto.

Tras el inicio de la aplicación o la inicialización del servlet, utilice la clase de Executors :

executor = Executors.newFixedThreadPool(10); // Max 10 threads.

Luego, durante el servicio del servlet (puede ignorar el resultado del caso que no le interesa):

Future<ReturnType> result = executor.submit(new CallableTask());

Finalmente, durante el cierre de la aplicación o la destrucción del servlet:

executor.shutdownNow(); // Returns list of undone tasks, for the case that.