Middle+
¿Qué es el marco Fork/Join y cómo se usa en Java?
sobes.tech AI
Respuesta de la IA
El marco Fork/Join es una implementación especializada del marco de trabajo Executor, diseñada para paralelizar tareas de manera eficiente, que pueden dividirse recursivamente en sub-tareas más pequeñas y luego unirse (join) sus resultados. Se basa en el principio de "divide y vencerás" (divide and conquer).
Componentes clave:
ForkJoinPool: Un grupo de hilos que gestiona la ejecución de tareas. Utiliza un mecanismo de "work-stealing", donde los hilos ociosos en el grupo pueden "robar" tareas de otros hilos que están ocupados.ForkJoinTask: Clase abstracta que representa una tarea que puede ser ejecutada en este marco. Tiene dos subtipos:RecursiveAction: Tarea que no devuelve resultado.RecursiveTask<V>: Tarea que devuelve un resultado de tipoV.
Uso:
- Crear una clase que herede de
RecursiveActionoRecursiveTask. - Sobrescribir el método
compute(). En este método se describe la lógica:- Si la tarea es lo suficientemente pequeña (menor que un umbral), se ejecuta directamente.
- En caso contrario, la tarea se divide en sub-tareas, que se ejecutan de forma asíncrona mediante
fork(). - Se espera a que las sub-tareas terminen con
join()y se unen sus resultados.
- Crear una instancia de
ForkJoinPool. - La tarea se envía al pool usando
invoke()osubmit().
Ejemplo:
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;
class SumArrayTask extends RecursiveTask<Long> {
private final long[] array;
private final int start;
private final int end;
private static final int THRESHOLD = 1000; // Umbral
public SumArrayTask(long[] array, int start, int end) {
this.array = array;
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
if (end - start <= THRESHOLD) {
long sum = 0;
for (int i = start; i < end; i++) {
sum += array[i];
}
return sum;
} else {
int mid = start + (end - start) / 2;
SumArrayTask leftTask = new SumArrayTask(array, start, mid);
SumArrayTask rightTask = new SumArrayTask(array, mid, end);
leftTask.fork();
Long rightResult = rightTask.compute();
Long leftResult = leftTask.join();
return leftResult + rightResult;
}
}
}
// Uso en código principal
// long[] data = new long[10000]; // Datos iniciales
// // Llenar data
// ForkJoinPool pool = new ForkJoinPool();
// long sum = pool.invoke(new SumArrayTask(data, 0, data.length));
// pool.shutdown(); // Cerrar el pool después del uso
Ventajas:
- Gestión automática del pool de hilos.
- Distribución eficiente de la carga gracias a work-stealing.
- Mejor rendimiento para tareas del tipo "divide y vencerás".
Desventajas:
- No apto para todos los tipos de tareas paralelas.
- Puede ser más difícil de implementar en comparación con otros enfoques para tareas simples.