Cómo forzar que CompletableFuture.thenApply() se ejecute en el mismo hilo que ejecutó la etapa anterior?
Aquí está una versión de código corto del problema que estoy enfrentando:
public static void main(String[] args) {
CompletableFuture.supplyAsync(() -> {
/*
try {
Thread.sleep(2000);
} catch (InterruptedException ignored) {}
*/
//System.out.println("supplyAsync: " + Thread.currentThread().getName());
return 1;
})
.thenApply(i -> {
System.out.println("apply: " + Thread.currentThread().getName());
return i + 1;
})
.thenAccept((i) -> {
System.out.println("accept: " + Thread.currentThread().getName());
System.out.println("result: " + i);
}).join();
}
Este es el resultado que obtengo:
apply: main
accept: main
result: 2
¡Me sorprende ver “main” allí! Esperaba algo como esto que sucede cuando descomento la llamada Thread.sleep()
o incluso descomento la única declaración sysout
allí:
supplyAsync: ForkJoinPool.commonPool-worker-1
apply: ForkJoinPool.commonPool-worker-1
accept: ForkJoinPool.commonPool-worker-1
result: 2
Entiendo que thenApplyAsync()
se asegurará de que no se ejecute en el hilo “main”, pero quiero evitar pasar los datos devueltos por el suministrador desde el hilo que ejecutó supplyAsync
al hilo que ejecutará thenApply
y los otros then
subsiguientes en la cadena.
davy.ai
La razón por la que ves
main
en la salida es porque la llamadasupplyAsync()
utiliza elForkJoinPool.commonPool()
por defecto, que es un conjunto compartido de hilos utilizado por la JVM para ejecutar tareas. En este caso, como no hay otras tareas que se estén ejecutando actualmente, el hilomain
se utiliza para ejecutar las llamadasthenApply()
ythenAccept()
.Si quieres evitar pasar los datos devueltos por el proveedor desde el hilo que ejecutó
supplyAsync()
hacia el hilo que ejecutaráthenApply()
y los demásthen
subsiguientes en la cadena, puedes utilizar el métodothenApplyAsync()
en lugar dethenApply()
. Esto asegurará que cada operación subsiguiente en la cadena se ejecute en un hilo separado al hilo que ejecutó la operación anterior, sin pasar ningún dato entre ellos.Aquí tienes una versión actualizada del código que utiliza
thenApplyAsync()
:Dado que estamos utilizando
thenApplyAsync()
, cada operación subsiguiente en la cadena se ejecutará en un hilo separado al hilo que ejecutó la operación anterior, sin pasar ningún dato entre ellos. Esto te dará la salida esperada:Ten en cuenta que los nombres exactos de los hilos pueden variar dependiendo del sistema y la configuración de la JVM.