Hola a todos!
Estamos lanzando la séptima secuencia del curso
Java Developer . En más de un año de la existencia de este curso, fue refinado, perfeccionado, se agregó uno nuevo que fue más allá de este tiempo. La misma secuencia difiere del resto en que introdujimos un nuevo sistema de pasos, dividiendo el curso en tres partes y aumentando ligeramente su duración total. Por lo tanto, ahora no será necesario estar exhausto durante cinco meses consecutivos para obtener un certificado, sino elegir con calma períodos de dos meses y recibir capacitación. Pero esta es la letra, volvamos a nuestra tradición sobre las diferentes utilidades que preceden al lanzamiento del curso.
Vamos
1. Descripción general
El contenedor de servlet de Java (o servidor web) es multiproceso: se pueden ejecutar simultáneamente varias solicitudes al mismo servlet. Por lo tanto, al escribir un servlet, debe considerar la competencia.
Como dijimos anteriormente, se crea una única instancia de servlet, y para cada nueva solicitud, Servlet Container crea un nuevo subproceso para ejecutar los métodos doGet () o doPost () del servlet.
Por defecto, los servlets no son seguros para subprocesos; el programador debe ocuparse de esto por sí mismo. En este capítulo, discutiremos la competencia de servlets. Este es un concepto muy importante, así que concéntrate.
2. Resumen de hilos

Un subproceso es un proceso ligero que tiene su propia pila de llamadas y accede a los datos abiertos de otros subprocesos en el mismo proceso (montón compartido). Cada hilo tiene su propio caché.
Cuando decimos que un programa es multiproceso, queremos decir que la misma instancia de un objeto genera varios hilos y procesa un solo elemento de código. Esto significa que varios flujos de control consecutivos pasan a través del mismo bloque de memoria. Por lo tanto, varios subprocesos ejecutan una instancia de un programa y, por lo tanto, comparten variables de instancia y pueden intentar leer y escribir estas variables compartidas.
Veamos un ejemplo simple de Java.
public class Counter { int counter=10; public void doSomething() { System.out.println(“Inital Counter = ” + counter); counter ++; System.out.println(“Post Increment Counter = ” + counter); } }
Ahora creamos dos hilos Thread1 y Thread2 para hacer
doSomething()
. Como resultado, es posible que:
- Thread1 lee un valor de contador de 10
- Muestra el contador inicial = 10 y va a aumentar
- Antes de que Thread1 incremente el contador, Thread2 también incrementa el contador, cambiando el contador a 11
- Como resultado, Thread1 tiene un valor de contador de 10, que ya está desactualizado
Este escenario es posible en un entorno de subprocesos múltiples, como servlets, porque las variables de instancia son compartidas por todos los subprocesos que se ejecutan en la misma instancia.
3. Escribir servlets seguros para subprocesos
Espero que en esta sección comprenda los problemas que estoy tratando de enfatizar. Si tiene dudas, lea el punto 2 nuevamente.
Hay algunos puntos que debemos tener en cuenta al escribir servlets.
Service()
, doGet()
, doPost()
o, más generalmente, los métodos doXXX()
no deben actualizar o modificar las variables de instancia, ya que las variables de instancia son compartidas por todos los hilos de la misma instancia.- Si es necesario modificar la variable de instancia, hágalo en un bloque sincronizado.
- Ambas reglas anteriores se aplican a las variables estáticas también porque también son comunes.
- Las variables locales siempre son seguras para subprocesos.
- Los objetos de solicitud y respuesta son seguros para el uso de subprocesos porque se crea una nueva instancia para cada solicitud en su servlet y, por lo tanto, para cada subproceso que se ejecuta en su servlet.
Los siguientes son dos enfoques para garantizar la seguridad de los hilos:
a) Sincronice el bloque en el que modifica la instancia o las variables estáticas (consulte el fragmento de código a continuación).
Recomendamos que sincronice el bloque en el que su código modifica las variables de instancia en lugar de sincronizar el método completo para mejorar el rendimiento.
Tenga en cuenta que debemos bloquear la instancia de servlet ya que debemos hacer que el subproceso de instancia de servlet específico sea seguro.
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class ThreadSafeServlet extends HttpServlet { @override public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException int counter; { synchronized (this) {
b) Modelo de subproceso único: implemente la interfaz SingleThreadModel para hacer que el subproceso sea de un solo subproceso, lo que significa que solo un subproceso ejecutará el método service () o doXXX () a la vez. Un servlet de subproceso único es más lento bajo carga porque las nuevas solicitudes deben esperar a que se procese una instancia gratuita
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class ThreadSafeServlet extends HttpServlet implements SingleThreadModel { int counter;
El uso de SingleThreadModel está en desuso, ya que se recomienda usar bloques sincronizados.
4. Conclusión
Debemos tener mucho cuidado al escribir servlets, porque "por defecto, los servlets no son seguros para subprocesos"
- Si su servlet no tiene ninguna variable estática o miembro, no necesita preocuparse y su servlet es seguro para subprocesos
- Si su servlet solo lee la variable de instancia, su servlet es seguro para subprocesos.
- Si necesita cambiar una instancia o variables estáticas, actualícela en un bloque sincronizado, manteniendo la instancia bloqueada
Si sigue las reglas anteriores y la próxima vez que alguien le pregunte: "¿Es seguro el hilo del servlet?" - responda con confianza: "Por defecto, no lo son, pero" Mis servlets "son seguros para subprocesos".
El fin
Como siempre, estamos esperando sus preguntas, sugerencias, etc. aquí o puede preguntarle a Sergey Petrelevich en la
lección Abierta sobre multihilo.