0Pricing
Java Academy · Lección

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=full para seguimientos completos
  • -Djdk.tracePinnedThreads=short para 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 synchronized bloqueante por ReentrantLock
  • Active jdk.tracePinnedThreads durante las pruebas
  • Minimice ThreadLocal; prefiera ScopedValue
  • 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 synchronized ocupa un hilo portador; soluciónelo con ReentrantLock
  • 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

  1. Qué son los hilos virtuales
  2. Creación de hilos virtuales
  3. Hilos de plataforma frente a hilos virtuales
  4. Errores: pinning y ThreadLocals
← Volver a Java Academy