Pasos prácticos para llevar tu código de StructuredTaskScope a JDK 28 tras la JEP 543: qué cambia desde JDK 27, JDK 25 y JDK 26, y cómo adaptarlo.
Tras siete rondas de preview, la concurrencia estructurada ya es una API final: la JEP 543 quedó integrada en JDK 28 sin cambios de API respecto a JDK 27. En esta guía repasamos cómo migrar según la versión de la que partas, qué forma tiene el código resultante y dónde conviene mirar con más cuidado.
La idea de fondo no ha cambiado desde el incubador de la JEP 428: tratar un grupo de subtareas en hilos distintos como una sola unidad de trabajo. Si una falla, las demás se cancelan, y el ámbito padre no termina hasta que todos los hilos hijos han acabado.
Lo que necesitas
Un proyecto que ya use StructuredTaskScope y un JDK 28 para compilar y probar. Ten a mano la documentación del paquete java.util.concurrent y localiza en tu código los joiners personalizados y los manejadores de excepciones alrededor de join().

Pasos de migración
- Identifica de qué versión partes: si estás en JDK 27, el cambio es mínimo; si vienes de JDK 25 o 26, hay adaptaciones de código.
- En JDK 27: elimina
--enable-previewde la compilación y de la ejecución, y recompila contra JDK 28. - En JDK 26: sustituye
FailedExceptionporExecutionExceptiony añade el parámetro de tipoR_Xen las firmas de tus joiners. - Revisa los timeouts:
StructuredTaskScope.TimeoutExceptiondesaparece y el fallo se comunica con una causaCancelledByTimeoutException; además,onTimeout()pasa a ser el método abstractotimeout(). - Busca usos de
Joiner.awaitAll(), que ya no existe, y sustitúyelos por la política que realmente necesites. - Ejecuta la batería de tests y comprueba especialmente los caminos de error y de cancelación.
Cómo queda el código final
El caso básico abre el ámbito con open(), lanza las subtareas con fork() (cada una en un hilo virtual por defecto) y espera con join(), que lanza ExecutionException si algo falla. Al cerrar el bloque try, se cancelan las subtareas pendientes y se espera a que sus hilos terminen.
Response handle() throws ExecutionException, InterruptedException {
try (var scope = StructuredTaskScope.open()) {
Subtask<String> user = scope.fork(() -> findUser());
Subtask<Integer> order = scope.fork(() -> fetchOrder());
scope.join(); // lanza ExecutionException si falla alguna
return new Response(user.get(), order.get());
}
}Para fijar un plazo y un nombre de ámbito (útil para observabilidad) se pasa una configuración a open(). Si el plazo vence, la causa de la ExecutionException será CancelledByTimeoutException, y puedes distinguirla con un switch sobre e.getCause().
try (var scope = StructuredTaskScope.open(
cf -> cf.withTimeout(Duration.ofSeconds(2)).withName("profile-page"))) {
Subtask<String> user = scope.fork(() -> findUser());
Subtask<Integer> order = scope.fork(() -> fetchOrder());
scope.join();
return new Response(user.get(), order.get());
}
Joiners personalizados
El tercer parámetro de tipo, R_X, permite que tu joiner declare su propia excepción y que join() la lance directamente, sin envolverla. Con un joiner de quórum, por ejemplo, join() lanzaría tu QuorumException. Su método timeout() debe lanzar esa misma excepción con CancelledByTimeoutException como causa.
Joiner.allSuccessfulOrThrow() devuelve una lista directamente, anySuccessfulOrThrow() devuelve el primer resultado válido y allUntil(Predicate) cancela cuando se cumple una condición. Escribe un joiner propio solo cuando ninguna encaje.Un último aviso: esta guía se basa en la descripción de la JEP y en el artículo de InfoQ sobre la finalización en JDK 28. La documentación enlazada es de acceso anticipado, así que contrasta los detalles con la versión definitiva de tu JDK antes de dar la migración por cerrada.
Fuente original: infoq.com
Artículo generado mediante AI.larebelion



Comentarios
Publicar un comentario