|
Documento sin título
Concurrencia en Servlets
Un problema típico generado por la naturaleza de las aplicaciones Web es el de Concurrencia.
Este problema se da cuando varios hilos de ejecución acceden a un recurso compartido. En particular este post analizará los problemas y soluciones de concurrencia en el manejo de Servlets.
Problema
Para presentar el problema, antes debemos hacer un paréntesis e indicar como funciona el ciclo de vida de un Servlet. El mismo tiene el siguiente comportamiento:
- Cuando se realiza una llamada sobre el servlet, si no se encuentra inicializado, se procede a hacer la carga en el Class Loader y luego la llamada al método init() en el servlet.
- Cada vez que se llama al servlet es invocado al método service() y este a los métodos concretos doPost(), doGet(), doXX()
- Cuando el Servlet se da de baja (ejemplo el servidor se baja) se remueve y llama al método destroy()
Por lo tanto podemos ver que cada vez que se llama al servlet se invoca al método service() sobre una única instancia.
Ahora imaginemos este método doGet en un servlet y un atributo como indica el comentario:
//atributo de counter
private int counter;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int myNumber = counter + 1; //problema!!
counter = myNumber;
//logica
counter = counter – 1;
}
Imaginemos ahora que en la línea con el comentario “problema!!”se ejecutan concurrentemente dos llamadas. El valor de la variable será incorrecto, produciendo en este caso un problema que no es real el valor.
Soluciones
El programador del Servlet debe resolver este problema
Dos formas de resolverlo
- Usar un bloque synchronized
- Usar el SingleThreadModel
Bloque synchronized
Debo agregar en un bloque synchronized cada vez que tengo un acceso potencialmente peligroso
Ejemplo
synchronized(this) {
myNumber = counter + 1;
counter = myNumber;
}
// logica
synchronized(this) {
counter = counter - 1 ;
}
SingleThreadModel
Los Servlets pueden implementar una interfaz de marca: javax.servlet.SingleThreadModel
Cuando el contenedor detecta la implementación de la interfaz maneja un pool de instancias del mismo Servlet que garantiza que un hilo de ejecución tiene una instancia única
Ejemplo
public class Servlet1 extends HttpServlet implements SingleThreadModel{
…
}
Aclaración y nota de SingleThreadModel
Este uso no resuelve todos los problemas de sincronización.
Ejemplo: atributos de sesión accedidas por varios servlets
Esta interfaz se encuentra “deprecated” en la versión 2.4 de la API Servlet.
En los JSP se puede indicar este comportamiento si agregamos el siguiente código:
<%@ page isThreadSafe="false" %>
Conclusión
- Es una buena práctica resolver los problemas de sincronización utilizando bloques synchronized siempre que sea posible.
- La solución con SingleThreadModel es más fácil que la de bloques sincronizados, pero agrega problemas de performance. Sin mencionar el estado de “deprecated” en la versión 2.4
|