Skip to content

Latest commit

 

History

History
148 lines (114 loc) · 5.98 KB

EXAMPLE3.adoc

File metadata and controls

148 lines (114 loc) · 5.98 KB

CompletableFuture Práctico

Ejemplos

3. Definiendo el número de tareas a ejecutar al mismo tiempo

En este ejemplo se muestra como definir el numero de tareas concurrentes, y como verificar los hilos o threads que se crean. Para este ejemplo se usa el mismo escenario del ejemplo 2 en el cual se realiza la consulta de las tareas asignadas a un grupo de desarrolladores, consultando la información de varios de ellos a la vez, una vez toda la información se encuentra cargada se consolida para retornar el resultado.

Para definir el número de tareas concurrentes se utiliza java.util.concurrent.Executor

Componentes

Clases
  • Developer: Entidad para representar desarrolladores

  • DeveloperService: Servicio en donde se consultan las tareas asignadas a cada desarrollador

Clases de pruebas

Código

En la clase DeveloperService se encuentra el método generateDeveloperCurrentStatusAsyncWithExecutor(Executor executor). Este método recibe como parámetro un java.util.concurrent.Executor.

En el método generateDeveloperCurrentStatusAsyncWithExecutor se hace el procesamiento concurrente y asíncrono, y con el fin de definir el número de tareas concurrentes se envía el executor al momento de crear el CompletableFuture según se muestra a continuación:

co.hillmerch.payments.DeveloperService::public List<Developer> generateDeveloperCurrentStatusAsyncWithExecutor(Executor executor)
for ( Developer developer : developerList ) {
    CompletableFuture cf = CompletableFuture
        .supplyAsync( () -> this.loadNumberOfTasks( developer ), executor)
        .thenRun( () -> printPoolInfo());
    cfList.add( cf );
}

Adicionalmente se ha creado el método private void printPoolInfo(), el cual imprime por consola el tamaño del pool y el nombre del hilo (Thread) en el cual se ejecuta la tarea. Este método se invoca en varias partes del código para poder observar como cambian estos valores.

co.hillmerch.payments.DeveloperService::private void printPoolInfo()
private void printPoolInfo(){
    System.out.println( "Pool size: " + ForkJoinPool.commonPool().getPoolSize()
            + ". Thread:  " + Thread.currentThread().getName());
}

Ejecución

En la clase de prueba co.hillmerch.developers.DeveloperServiceTest el método void testingGenerateDeveloperCurrentStatusAsyncWithExecutors() permite ejecutar el método en el que se define el executor. En este ejercicio usamos 3: Executors.newSingleThreadExecutor(), ForkJoinPool.commonPool() y Executors.newFixedThreadPool(int nThreads)

Análisis de resultados (Ejecución de casos de pruebas)

A continuación se analizan los resultados de cada uno de los 3 executors definidos.

  • Executors.newSingleThreadExecutor(): Este executor define un solo thread, esto significa que aunque el método sea concurrente y asíncrono solo se ejecutará una tarea a la vez, tal como se puede observar en la salida al ejecutar el método solo se uso el thread llamado pool-1-thread-1

Pool size: 0. Thread:  main
Pool size: 0. Thread:  main
Pool size: 0. Thread:  pool-1-thread-1
Pool size: 0. Thread:  pool-1-thread-1
Pool size: 0. Thread:  pool-1-thread-1
Pool size: 0. Thread:  pool-1-thread-1
Pool size: 0. Thread:  pool-1-thread-1
Pool size: 0. Thread:  pool-1-thread-1
Pool size: 0. Thread:  pool-1-thread-1
Pool size: 0. Thread:  pool-1-thread-1
Pool size: 0. Thread:  pool-1-thread-1
Pool size: 0. Thread:  pool-1-thread-1
Pool size: 0. Thread:  main
  • ForkJoinPool.commonPool(): Este ejecutor definir el número de threads de manera estática cuando se necesiten por la máquina virtual. En este caso se puede observar que el pool inició con 0 hilos, y al momento de iniciar la ejecución concurrente se crearon tres: commonPool-worker-n donde n corresponde a 3, 5 y 7.

Pool size: 0. Thread:  main
Pool size: 2. Thread:  main
Pool size: 3. Thread:  ForkJoinPool.commonPool-worker-5
Pool size: 3. Thread:  ForkJoinPool.commonPool-worker-7
Pool size: 3. Thread:  ForkJoinPool.commonPool-worker-3
Pool size: 3. Thread:  ForkJoinPool.commonPool-worker-7
Pool size: 3. Thread:  ForkJoinPool.commonPool-worker-5
Pool size: 3. Thread:  ForkJoinPool.commonPool-worker-3
Pool size: 3. Thread:  ForkJoinPool.commonPool-worker-7
Pool size: 3. Thread:  ForkJoinPool.commonPool-worker-5
Pool size: 3. Thread:  ForkJoinPool.commonPool-worker-3
Pool size: 3. Thread:  ForkJoinPool.commonPool-worker-7
Pool size: 3. Thread:  main
  • Executors.newFixedThreadPool(50): Este ejecutor permite definir el número de threads que se quieren destinar para la ejecución concurrente, en este caso se definió con el valor de 50, y como se puede observar en la salida se han creado 10 hilos pool-2-thread-n donde n va desde 1 hasta 10, uno por cada registro.

Pool size: 3. Thread:  main
Pool size: 3. Thread:  main
Pool size: 3. Thread:  pool-2-thread-2
Pool size: 3. Thread:  pool-2-thread-4
Pool size: 3. Thread:  pool-2-thread-6
Pool size: 3. Thread:  pool-2-thread-5
Pool size: 3. Thread:  pool-2-thread-1
Pool size: 3. Thread:  pool-2-thread-8
Pool size: 3. Thread:  pool-2-thread-3
Pool size: 3. Thread:  pool-2-thread-7
Pool size: 3. Thread:  pool-2-thread-9
Pool size: 3. Thread:  pool-2-thread-10
Pool size: 3. Thread:  main

Conclusión

En este ejemplo podemos concluir:

  1. La clase CompletableFuture permite definir la estrategia o numero de tareas concurrentes en las cuales se quiere dividir el procesamiento.

  2. Cuando no se define un executor, se usará por defecto ForkJoinPool.commonPool()

  3. La selección de el executor depende del caso de uso, los datos a procesar y/o los recursos de hardware disponibles