Tabla de Contenidos

11 - Hilos en Tomcat

Un servidor web atiende muchas peticiones a la vez. En Tomcat, cada petición la procesa un hilo; entender cómo se reparten y reutilizan es necesario para decidir qué estado puede guardarse y dónde.

1. Cada petición se atiende en un hilo

Tomcat mantiene un pool de hilos con hilos worker disponibles. Cuando llega una petición HTTP, se asigna a un hilo libre; al terminar la respuesta, el hilo vuelve al pool y puede atender otra petición.

Peticiones En qué hilos se ejecutan
Simultáneas Cada una se ejecuta en un hilo distinto
Sucesivas Pueden ejecutarse en el mismo hilo reutilizado

Cliente ACliente BCliente CTomcatHilo 1Hilo 2Cliente ACliente BCliente CTomcatHilo 1Hilo 2Cliente ACliente BCliente CTomcatHilo 1Hilo 2Petición Ala atiende el hilo 1Petición B (simultánea)la atiende el hilo 2respuestarespuestaPetición C (posterior)reutiliza el hilo 1respuesta

2. Estado compartido entre hilos

Un campo static pertenece a la clase: todos los hilos ven y modifican el mismo valor.

public class SharedValue {
    private static volatile String value;

    public static void setValue(String newValue) {
        value = newValue;
    }

    public static String getValue() {
        return value;
    }
}

Si dos peticiones fijan valores distintos a la vez, la segunda puede sobrescribir el valor antes de que la primera lo lea: una petición trabaja con el valor de otra. Es una condición de carrera: el resultado depende del orden temporal en que se ejecutan los hilos.

volatile no crea un valor distinto para cada hilo: el campo static sigue siendo único y compartido. La diferencia es qué garantía hay al leer escrituras de otros hilos:

Hilo A: escribe "A"
Hilo B: escribe "B"
Hilo A: lee el campo

En ambos casos hay acceso compartido. volatile garantiza visibilidad, pero no evita que una escritura sobrescriba otra ni hace indivisible una secuencia de operaciones. Por tanto, no evita la condición de carrera.

Campo static Variable local
Un único valor visible para todos los hilos Cada hilo tiene la suya en su propia pila
Requiere cuidado ante accesos concurrentes No se comparte entre peticiones

3. ThreadLocal: un valor por hilo, no por petición

ThreadLocal guarda un valor distinto para cada hilo: cada hilo solo ve el suyo.

public class ThreadData {
    private static final ThreadLocal<String> DATA_BY_THREAD = new ThreadLocal<>();

    public static void setData(String data) {
        DATA_BY_THREAD.set(data);
    }

    public static String getData() {
        return DATA_BY_THREAD.get();
    }

    public static void clearData() {
        DATA_BY_THREAD.remove();
    }
}

Pero el valor es por hilo, no por petición. Como Tomcat reutiliza los hilos, el valor fijado durante una petición sigue ahí cuando el mismo hilo atiende la siguiente: la nueva petición encontraría un valor que no le corresponde. Es una fuga de datos entre peticiones.