package ar.com.javacuriosities.concurrency.fork_join; import java.security.SecureRandom; import java.util.Random; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask; /* * El framework Fork/Join (Incluido en Java 1.7) es una implementación de ExecutorService con mejoras para el multiproceso. * Está diseñado para dividir una tarea grande en varias pequeñas. El objetivo es aprovechar mejor * toda la capacidad de procesamiento y mejorar el rendimiento de las aplicaciones. * Al igual que con ExecutorService, tendremos un pool de Threads con una cola de tareas asociada, * la diferencia estará en la forma de procesar estas tareas. * El framework fork/join implementa el algoritmo work-stealing, que dice que los threads de trabajo que * quedan sin cosas que hacer pueden robar tareas de otros threads que aún están ocupados. * Dicho de otra manera, dice que un thread que está a la espera la finalización de otros threads, * busca tareas que no han sido ejecutados y los ejecuta. * * Veamos las clases principales del framework * * La clase java.util.concurrent.ForkJoinPool implementa la interfaz ExecutorSevice y también implementa el algoritmo work-stealing. * * La clase java.util.concurrent.ForkJoinTask implementa la interfaz Future, la cual * es una clase abstracta para las tareas que se ejecutan en el ForkJoinPool, provee el método fork() * para organizar la ejecución asíncrona y el método join() para continuar hasta que el resultado de la tarea se ha calculado. * * La clase java.util.concurrent.RecursiveAction, esta tarea implementa su lógica en el método compute(), * este método suele tener la siguiente lógica * * if (el problema es lo suficientemente pequeño) { * resolvemos el problema * } else { * fork: dividimos el problema en partes pequeñas * join: esperamos por cada parte a ser resuelta * compose: juntamos los distintos resultados * } * */ public class Main { public static void main(String[] args) { // Creamos un arreglo con numeros random int[] data = new int[1000]; Random random = new SecureRandom(); for (int i = 0; i < data.length; i++) { data[i] = random.nextInt(50000); } ForkJoinPool pool = new ForkJoinPool(); MaximumFinder finder = new MaximumFinder(data); System.out.println("The maximum value is: " + pool.invoke(finder)); } private static final class MaximumFinder extends RecursiveTask<Integer> { private static final long serialVersionUID = 1L; private static final int SEQUENTIAL_THRESHOLD = 5; private final int end; private final int start; private final int[] data; public MaximumFinder(int[] data) { this(data, 0, data.length); } public MaximumFinder(int[] data, int start, int end) { this.end = end; this.data = data; this.start = start; } @Override protected Integer compute() { int length = end - start; if (length < SEQUENTIAL_THRESHOLD) { return computeDirectly(); } int split = length / 2; MaximumFinder left = new MaximumFinder(data, start, start + split); MaximumFinder right = new MaximumFinder(data, start + split, end); left.fork(); return Math.max(right.compute(), left.join()); } private Integer computeDirectly() { System.out.println(Thread.currentThread() + " computing: " + start + " to " + end); int max = Integer.MIN_VALUE; for (int i = start; i < end; i++) { if (data[i] > max) { max = data[i]; } } return max; } } }