Errores: pinning y ThreadLocals
Evite bloquear los hilos portadores
Errores: pinning y ThreadLocals es una lección gratuita de Java Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Java Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Java Academy incluye 4 lecciones en total.
Qué puede salir mal
Los hilos virtuales son potentes, pero dos problemas pueden socavar silenciosamente su escalabilidad: el pinning y el uso excesivo de ThreadLocal.
En esta lección se explican ambos y cómo evitarlos.
Qué es el pinning
El pinning ocurre cuando un hilo virtual no puede desmontarse de su hilo portador mientras está bloqueado. El hilo del sistema operativo que actúa como portador permanece bloqueado, anulando la ventaja de escalabilidad.
Cuando demasiados hilos portadores están fijados, el rendimiento se desploma.
Causa: bloqueo con synchronized
La causa clásica es bloquear dentro de un bloque o método synchronized. Al mantener el monitor y bloquearse después, el hilo virtual permanece fijado a su hilo portador.
Nota: en JDK 24+ (JEP 491), esta limitación se eliminó en gran medida, pero en Java 21 es una preocupación real.
Ejemplo de pinning que debe evitarse
Este patrón puede provocar pinning en Java 21: bloquearse mientras se mantiene un monitor. Sigue ejecutándose correctamente, pero no escala.
public class Main {
static final Object lock = new Object();
static void risky() {
synchronized (lock) {
try { Thread.sleep(10); } catch (InterruptedException e) {}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = Thread.ofVirtual().start(Main::risky);
t.join();
System.out.println("Done (but this blocked inside synchronized)");
}
}La solución: ReentrantLock
Reemplace synchronized por ReentrantLock cuando la sección crítica pueda bloquearse. Las API de bloqueo son adecuadas para los hilos virtuales y permiten desmontarlos.
import java.util.concurrent.locks.ReentrantLock;
public class Main {
static final ReentrantLock lock = new ReentrantLock();
static void safe() {
lock.lock();
try {
try { Thread.sleep(10); } catch (InterruptedException e) {}
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = Thread.ofVirtual().start(Main::safe);
t.join();
System.out.println("Done without pinning");
}
}Diagnosticar el pinning
Puede pedir a la JVM que muestre un seguimiento de la pila cada vez que se produzca pinning iniciándola con:
-Djdk.tracePinnedThreads=fullpara seguimientos completos-Djdk.tracePinnedThreads=shortpara líneas breves
Esto le ayuda a localizar las secciones synchronized problemáticas.
ThreadLocal se vuelve costoso
ThreadLocal almacena el estado específico de cada hilo. Con unos pocos hilos de plataforma, no hay problema. Con millones de hilos virtuales, cada uno con su propia copia, el consumo de memoria se dispara.
Audite sus bibliotecas: el almacenamiento en caché, el formateo y los objetos de contexto suelen ocultar ThreadLocal.
ThreadLocal sigue funcionando
ThreadLocal no está prohibido; simplemente úselo con moderación. Cada hilo virtual obtiene su propio valor, como se espera.
public class Main {
static final ThreadLocal<String> CONTEXT = new ThreadLocal<>();
public static void main(String[] args) throws InterruptedException {
Thread t = Thread.ofVirtual().start(() -> {
CONTEXT.set("request-42");
System.out.println("Context: " + CONTEXT.get());
CONTEXT.remove();
});
t.join();
}
}Prefiera ScopedValue
Java introdujo ScopedValue como una alternativa más ligera para compartir datos inmutables durante un tiempo de vida limitado. Evita el coste del almacenamiento mutable por hilo de ThreadLocal y encaja con el modelo de concurrencia estructurada.
Cuando solo necesite pasar un contexto de solo lectura a lo largo de una cadena de llamadas, elija esta opción.
No cree pools
Otro problema sutil es tratar los hilos virtuales como un recurso escaso y agruparlos en un pool. Esto vuelve a introducir contención y filtraciones de ThreadLocal entre tareas.
Cree siempre un hilo virtual por tarea y deje que termine.
Lista de comprobación de escalabilidad
Antes de poner los hilos virtuales en producción:
- Reemplace
synchronizedbloqueante porReentrantLock - Active
jdk.tracePinnedThreadsdurante las pruebas - Minimice
ThreadLocal; prefieraScopedValue - Nunca agrupe los hilos virtuales en un pool
Comprobación rápida
Identifique el reemplazo seguro para un bloque synchronized bloqueante.
Resumen
Ha aprendido los principales problemas:
- Pinning: bloquear dentro de
synchronizedocupa un hilo portador; soluciónelo conReentrantLock - Diagnostique el problema con
-Djdk.tracePinnedThreads - El coste de ThreadLocal aumenta con el número de hilos; prefiera
ScopedValue - Nunca agrupe los hilos virtuales en un pool
Con esto concluye el curso de Virtual Threads.
Preguntas frecuentes
¿La lección «Errores: pinning y ThreadLocals» es gratis?
Sí — el texto completo de «Errores: pinning y ThreadLocals» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Java Academy, actualiza a CoddyKit PRO. El curso de Java Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Errores: pinning y ThreadLocals»?
Evite bloquear los hilos portadores Practicas Java Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Java Academy?
No se requiere experiencia previa. Java Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.
¿Cuánto tiempo toma la lección «Errores: pinning y ThreadLocals»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Java Academy?
Sí. Cada lección de Java Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Qué son los hilos virtuales
- Creación de hilos virtuales
- Hilos de plataforma frente a hilos virtuales
- Errores: pinning y ThreadLocals