En el modelo tradicional de servlets, es normalmente el caso de que la solicitud 1 corresponde a 1 hilo.
Por lo general, estos subprocesos provienen de un grupo que está administrado por el contenedor Servlet. El contenedor Servlet solo puede manejar nuevas solicitudes siempre que tenga hilos libres en este grupo. Siempre que su propio código esté ocupado procesando la solicitud, el hilo no es gratis.
En algunas situaciones, valdría la pena romper este modelo. Lo que sucede es que una solicitud llega al Servlet a través de dicho subproceso administrado en un contenedor Servlet y su código solicita una ejecución asíncrona. Luego puede regresar desde la solicitud del servlet y se liberará el hilo del contenedor.
Contrariamente al procesamiento de solicitudes sincrónicas, esto no confirmará ninguna respuesta y no cerrará la conexión. En su lugar, puede transferir el contexto asincrónico a otro grupo de subprocesos, que puede recogerlo, y cuando algún subproceso es libre de manejarlo, preséntelo y podrá escribir en la respuesta.
Un ejemplo:
@WebServlet(urlPatterns = "/somepath", asyncSupported = true)
public class AsyncServlet extends HttpServlet {
@EJB
private AsyncBean asyncBean;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
AsyncContext asyncContext = request.startAsync();
// The following line will not block and return immediately
asyncBean.doAsyncStuff(asyncContext);
} // Shortly after this method has ended, thread will be returned to pool
}
Con la AsyncBean
se implementan como:
@Stateless
public class AsyncBean {
@Asynchronous
public void doAsyncStuff(AsyncContext asyncContext) throws IOException {
asyncContext.getResponse().getWriter().write("test");
}
}
En el código anterior, en algún lugar poco después de que regrese a partir del método AsyncServlet#doGet()
, el hilo servlet será devuelto a la piscina. Se habrá puesto una 'solicitud' (tarea) para ejecutar AsyncBean#doAsyncStuff()
en la cola para que se recoja el grupo de subprocesos EJB.
La respuesta a POR QUÉ y CUÁNDO usaría esto no es tan sencillo. Si solo desea conservar los hilos, en el caso anterior intercambiará uno por un hilo de un grupo de hilos por el otro (en este caso, el grupo Servlet frente al conjunto asincrónico EJB) y el beneficio neto no sería demasiado. También podría haberle dado a su conjunto de subprocesos de Servlet un hilo adicional.
En los escenarios más avanzados, sin embargo, podría hacer una administración más detallada de las solicitudes; divídalos en tareas múltiples y tenga un servicio de agrupamiento de subprocesos esas tareas. P.ej. Imagine 100 solicitudes de descarga para un archivo de 10 MB manejado por 10 subprocesos que round-robin give envía 100 KB cada vez.
Otra aplicación es una solicitud que necesita esperar datos de un sistema externo, y donde este sistema externo puede enviar un mensaje que se puede retransmitir al solicitante. Es decir. una llamada a la base de datos no tendría sentido aquí, ya que necesitaría otro hilo esperando la respuesta de todos modos. Entonces cambiarías un hilo por otro nuevamente. Pero si necesita esperar para decir un correo electrónico entrante, entonces un hilo puede esperar cualquier correo electrónico y retransmitirlo a cualquier solicitud suspendida.
Muchas gracias Arjan, el primer párrafo es muy claro y comprensible. –
No entiendo completamente cómo mover un hilo de un grupo a otro puede marcar la diferencia desde el punto de vista de la escalabilidad. Veo el sentido de devolver el hilo de escucha del servidor al grupo, pero realmente no sé si eso puede mejorar mucho la escalabilidad de la aplicación. –
Intercambiar subprocesos no ayudará con la escalabilidad, pero vea el ejemplo de descarga. Algunos hilos podrían alimentar muchas conexiones asíncronas. Si la solicitud se puede dividir en varias tareas que pueden ponerse en cola y tal, puede valer la pena considerar este modo. De lo contrario, de hecho, no hay muchos beneficios esperados. –