Prompt y alcance
Un entrevistador podría preguntar: “¿Qué problema resuelve ScopedValue en Java 25? Compárelo con ThreadLocal y explique su uso correcto con grupos de hilos (thread pools) o hilos virtuales (virtual threads)”.
JEP 506 finalizó Scoped Values en JDK 25. Permiten que un invocador comparta datos inmutables con invocados profundos e hilos secundarios dentro de un ámbito léxico, reduciendo la necesidad de pasar el contexto a través de cada parámetro de método. La pregunta evalúa el ciclo de vida, la visibilidad y los límites de concurrencia; no se responde simplemente calificando a ScopedValue como “un nuevo ThreadLocal”.
Qué está evaluando el entrevistador
- Si comprende ScopedValue como un parámetro implícito, inmutable y controlado por ámbito.
- Si puede explicar el enlace y la restauración de
where(...).run(...)ocall(...). - Si reconoce las diferencias respecto a un ThreadLocal mutable, la reutilización de hilos en pools y la herencia en hilos virtuales.
- Si considera el control de acceso a las claves, la cantidad de enlaces, la propagación de excepciones y la cancelación.
- Si sabe cuándo los parámetros explícitos o ThreadLocal siguen siendo adecuados.
Preguntas para clarificar
- ¿Es el valor compartido un ID de solicitud, un principal, un tenant o un estado de transacción mutable?
- ¿Debe ser de solo lectura y deberían heredarlo las tareas secundarias?
- ¿La ejecución se realiza en hilos de plataforma, hilos virtuales, concurrencia estructurada o en un pool existente?
- ¿Podría el código leer la clave fuera de su ámbito o exponer un Carrier a código no confiable?
- ¿Depende el framework de la limpieza de ThreadLocal, de la mutación o de la integración con MDC?
Una respuesta de 30 segundos
Puede decir:
ScopedValue es el mecanismo de contexto inmutable y de ámbito léxico de Java 25. Un invocador crea un enlace conScopedValue.where(key, value).run(...)ocall(...); este se restaura cuando el ámbito finaliza, y solo el código que posee la clave puede leerlo. En comparación con ThreadLocal, reduce la limpieza en hilos reutilizados de pools y las fugas de estado mutable, lo que lo hace útil para el contexto de solicitudes, hilos virtuales y concurrencia estructurada. No reemplaza a un ThreadLocal que debe actualizarse paso a paso, y un valor no debe escapar de su ámbito. Probaría la herencia, las excepciones, la cancelación y la visibilidad de las claves en el JDK de destino.
Razonamiento paso a paso
Comprender el modelo de enlace
El valor es legible durante el rango de ejecución dinámica, mientras que el enlace se hace explícito mediante la estructura del código:
static final ScopedValue<String> REQUEST_ID = ScopedValue.newInstance();
ScopedValue.where(REQUEST_ID, "req-42").run(() -> {
audit("start");
handleRequest();
});
static void audit(String message) {
logger.info("{} {}", REQUEST_ID.orElse("missing"), message);
}audit no necesita un parámetro de ID de solicitud, pero lee un valor significativo solo dentro del ámbito del enlace. Una vez que el ámbito finaliza, el enlace no puede contaminar el hilo del invocador.
Comparar la mutabilidad de ThreadLocal
ThreadLocal otorga a cada hilo un valor mutable; la reutilización de hilos en pools requiere limpieza o la siguiente solicitud podría observar un contexto obsoleto. ScopedValue está diseñado para el uso compartido inmutable, con enlaces anidados que ocultan temporalmente (shadow) un valor externo y lo restauran después. Reduce la responsabilidad de limpieza, pero no transporta una máquina de estados que el código profundo deba set repetidamente.
Manejar tareas secundarias e hilos virtuales
JEP 506 apunta a costos de compartición predecibles con hilos virtuales y concurrencia estructurada. Si la herencia ocurre, cuándo se captura y cómo se comporta un ejecutor debe verificarse contra el JDK de destino y el contrato de la API; no traslade suposiciones de un grupo de hilos ordinario. El objeto compartido debe permanecer inmutable para que una referencia no pueda eludir el límite del contexto.
Diseñar claves, excepciones y compatibilidad
Haga que una clave sea un objeto private static final o parte de una API controlada. No trate una clave compartida globalmente como un límite de seguridad. Use orElse o una excepción explícita para un valor faltante; en Java 25, orElse ya no acepta null. Una excepción que sale de run o call aún sale del ámbito y restaura el enlace externo. Para JDKs más antiguos, mantenga parámetros explícitos o una implementación de ThreadLocal detrás de una ruta de compatibilidad probada.
Respuesta modelo de alta calidad
Trato a ScopedValue como un parámetro implícito inmutable, no como un reemplazo mutable para ThreadLocal. El punto de entrada de la solicitud crea un ámbito estructurado conwhere(key, value).runocall; los métodos profundos leen un ID de solicitud, tenant o principal a través de la clave, y el enlace se restaura al salir. Se adapta al contexto de solo lectura en hilos virtuales y concurrencia estructurada, y evita fugas por limpieza en hilos de pools. ThreadLocal sigue siendo útil para el estado que debe actualizarse paso a paso, con limpieza en finally. Restringiría la visibilidad de las claves, probaría la herencia en tareas secundarias, excepciones, cancelación, sombreado anidado y lecturas fuera del ámbito, y mantendría una implementación explícita o compatible para JDKs anteriores.
Errores comunes
- Llamar a ScopedValue un ThreadLocal mutable con limpieza automática.
- Guardar un Carrier o un valor fuera del ámbito, o leer una clave después de su ciclo de vida.
- Ignorar la reutilización de hilos en pools, la herencia en tareas secundarias y las diferencias de los hilos virtuales.
- Almacenar un objeto mutable mientras se afirma que todo el contexto es inmutable.
- Compartir una clave entre módulos arbitrarios y confundir el control de acceso con cifrado.
- Olvidar la regla non-null de
orElsede Java 25 u omitir una ruta para JDKs más antiguos.
Preguntas de seguimiento y respuestas
1. ¿Puede ScopedValue reemplazar todos los ThreadLocal?
No. Se adapta a contextos de solo lectura y delimitados por un ámbito. El estado que debe actualizarse a través de una cadena de llamadas aún puede usar ThreadLocal o parámetros explícitos, con la responsabilidad de limpieza requerida.
2. ¿Qué sucede con los enlaces anidados?
Un ámbito interno puede enlazar temporalmente un nuevo valor para la misma clave; salir de él restaura el valor externo. Las rutas de excepción también salen del ámbito, por lo que el valor interno no se filtra hacia afuera.
3. ¿Cómo prueba la herencia concurrente?
Cubra hilos de plataforma, hilos virtuales, tareas estructuradas y reutilización de hilos en pools. Verifique el valor visto por las tareas secundarias, la limpieza después de la cancelación, el sombreado anidado y las lecturas fuera del ámbito. Fije la versión del JDK y la configuración del ejecutor en la matriz de pruebas.