es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

La función parallelStream() de Java 17 genera problemas críticos de rendimiento en el código que funciona correctamente en Java 16. ¿Por qué sucede esto?

Trabajo en una aplicación web Jetty que se ejecutaba en Java 16. Intenté actualizarla a Java 17, pero hubo problemas críticos de rendimiento causados enteramente por una llamada a parallelStream().

Los únicos cambios son la actualización de la versión de Java de 16 a 17, --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED y la actualización del tiempo de ejecución de openjdk:16.0.1-jdk-oraclelinux8 a openjdk:17.0.1-jdk-oraclelinux8.

Logramos obtener un volcado de hilos y contiene muchos de estos:

"qtp1368594774-200" #200 prio=5 os_prio=0 cpu=475.94ms elapsed=7189.65s tid=0x00007fd49c50cc10 nid=0xd1 waiting on condition  [0x00007fd48fef7000]
   Estado del hilo java.lang.Thread: ESPERANDO (estacionamiento)
    en jdk.internal.misc.Unsafe.park(java.base@17.0.1/Native Method)
    - estacionándose para esperar a  <0x00000007b73439a8> (un java.util.stream.ReduceOps$ReduceTask)
    en java.util.concurrent.locks.LockSupport.park(java.base@17.0.1/LockSupport.java:341)
    en java.util.concurrent.ForkJoinTask.awaitDone(java.base@17.0.1/ForkJoinTask.java:468)
    en java.util.concurrent.ForkJoinTask.invoke(java.base@17.0.1/ForkJoinTask.java:687)
    en java.util.stream.ReduceOps$ReduceOp.evaluateParallel(java.base@17.0.1/ReduceOps.java:927)
    en java.util.stream.AbstractPipeline.evaluate(java.base@17.0.1/AbstractPipeline.java:233)
    en java.util.stream.ReferencePipeline.collect(java.base@17.0.1/ReferencePipeline.java:682)
    en com.stackoverflowexample.aMethodThatDoesBlockingIOUsingParallelStream()

El código que está causando el problema es algo como:

list.parallelStream()
.map(this::callRestServiceToGetSomeData)
.collect(Collectors.toUnmodifiableList());

Esta imagen muestra el uso de hilos antes de la actualización de jdk16 (izquierda), la actualización a jdk17 (el pico enorme en el medio), y luego eliminando la llamada a parallelStream() aún en jdk17 (derecha):

Threads

¿Qué cambio en Java 17 (openjdk-17.0.1linux-x64bin.tar.gz) ha causado esto?

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    El problema se debe a un cambio en la forma en que se maneja ForkJoinTask en Java 17. Específicamente, se agregó una nueva función llamada “FJ Tasks interruptible in park” en Java 17, que permite interrumpir ForkJoinTask cuando están bloqueados en una llamada a park().

    En el código proporcionado, la llamada parallelStream() está haciendo que los hilos se bloqueen en una llamada a park(), esperando a que el ForkJoinTask se complete. Sin embargo, debido a que Java 17 introdujo la capacidad de interrumpir ForkJoinTask en park, los hilos se interrumpen y se reprograman, lo que provoca un gran aumento en el uso de hilos.

    Para solucionar este problema, una solución es cambiar de usar parallelStream() a usar stream() en su lugar, lo cual evitará que los hilos se bloqueen y evitará el impacto en el rendimiento causado por ForkJoinTask interrumpible.

    Alternativamente, si es necesario utilizar parallelStream(), puede intentar aumentar el número de hilos en ForkJoinPool configurando la propiedad del sistema java.util.concurrent.ForkJoinPool.common.parallelism a un valor más alto, lo cual puede ayudar a aliviar el impacto en el rendimiento causado por ForkJoinTask interrumpible.

Comments are closed.