Este artículo presenta una clase de utilidad en Java diseñada parra procesar datos de una lista utilizando múltiples hilos, facilitendo la ejecución concurrente de tareas en lotes.
Dependencia de Maven
Se utiliza la biblioteca Guava para dividir listas. Agregue la siguiente dependencia a su proyecto Maven:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
Clase de Utilidad
La siguiente clase proporciona métodos para ejecutar operaciones en paralelo sobre una lista, permitiendo configurar el número de hilos y el tamaño mínimo del lote.
import com.google.common.collect.Lists;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
public class ProcesadorListasParalelo {
/**
* Ejecuta una operación de consumo en una lista utilizando múltiples hilos.
*
* @param datosEntrada lista de datos a procesar
* @param cantidadHilos número de hilos a utilizar
* @param accionConsumo función que define el procesamiento de cada sublista
*/
public static void procesarConHilos(List<?> datosEntrada, int cantidadHilos, Consumer<List<?>> accionConsumo) {
procesarConHilos(datosEntrada, cantidadHilos, 0, accionConsumo);
}
/**
* Ejecuta una operación de consumo en una lista con control de tamaño mínimo del lote.
*
* @param datosEntrada lista de datos a procesar
* @param cantidadHilos número de hilos a utilizar
* @param tamanoLoteMinimo tamaño mínimo para aplicar paralelismo; si es cero, se ignora
* @param accionConsumo función que define el procesamiento de cada sublista
*/
public static void procesarConHilos(List<?> datosEntrada, int cantidadHilos, int tamanoLoteMinimo, Consumer<List<?>> accionConsumo) {
if (datosEntrada == null || datosEntrada.isEmpty()) {
return;
}
int tamanoParticion = 1;
if (cantidadHilos > 0 && (tamanoLoteMinimo == 0 || datosEntrada.size() > tamanoLoteMinimo)) {
tamanoParticion = (datosEntrada.size() / cantidadHilos) + 1;
}
List<? extends List<?>> sublistas = Lists.partition(datosEntrada, tamanoParticion);
ExecutorService poolHilos = Executors.newFixedThreadPool(cantidadHilos > 0 ? cantidadHilos : 1);
try {
for (List<?> lote : sublistas) {
poolHilos.submit(() -> {
accionConsumo.accept(lote);
});
}
} catch (Exception excepcion) {
throw new RuntimeException("Error durante la ejecución multihilo: " + excepcion.getMessage(), excepcion);
} finally {
poolHilos.shutdown();
try {
if (!poolHilos.awaitTermination(24, TimeUnit.HOURS)) {
poolHilos.shutdownNow();
}
} catch (InterruptedException interrupcion) {
Thread.currentThread().interrupt();
poolHilos.shutdownNow();
}
}
}
}
Ejemplo de Uso
A continuación, se muestra un ejemplo básico de cómo utilizar la utilidad para procesar una lista de cadenas.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class EjemploUso {
public static void main(String[] args) {
List<String> elementos = Arrays.asList("alpha", "beta", "gamma", "delta", "epsilon");
ProcesadorListasParalelo.procesarConHilos(elementos, 3, 2, lote -> {
for (String item : lote) {
System.out.println("Hilo " + Thread.currentThread().getName() + " procesa: " + item);
}
});
}
}
Este código dividirá la lista en lotes y los procesará en paralelo, imprimiendo el hilo repsonsable y el elemento procesado.