Crea un Thread Pool en Java


Un Thread pool en Java administra una colección de workers y threads ejecutables.

1.- Creando el hilo trabajador(worker)

El primer paso es crear un hilo, en este ejemplo se creará un hilo trabajador que recibirá 3 parámetros un arreglo, un indice de inicio y un indice de fin e imprimirá los valores del arreglo que se encuentren en el rango.

/**
 *
 */
package com.raidentrance.threads;

/**
 * @author raidentrance
 *
 */
public class PrintArrayThread implements Runnable {

	private int[] array;
	private int start;
	private int end;

	public PrintArrayThread(int[] array, int start, int end) {
		this.array = array;
		this.start = start;
		this.end = end;
	}

	public void run() {
		for (int i = start; i < end; i++) {
			System.out.println(
					String.format("Current thread %s printing value %s", Thread.currentThread().getName(), array[i]));
		}
	}

}

2.-Creando el Thread Pool

Una vez creado el worker los siguientes pasos serán los siguientes:

  • Crear e inicializar el arreglo base que se pasará como parámetro a los hilos
  •  Crear el ThreadPool y especificar el número de hilos que se utilizaran, para este ejemplo se utilizarán 3 hilos
  • Ejecutar los hilos que realizarán el trabajo
  • Detener el Thread pool
  • Esperar a que todos los hilos terminen su ejecución
/**
 *
 */
package com.raidentrance.threads;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author raidentrance
 *
 */
public class ThreadPoolExample {
	public static void main(String[] args) {

		int bigArray[] = new int[100000];
		for (int i = 0; i < bigArray.length; i++) {
			bigArray[i] = new Random().nextInt(100);
		}

		ExecutorService executor = Executors.newFixedThreadPool(3);
		for (int i = 0; i < 10; i++) {
			Runnable worker = new PrintArrayThread(bigArray, i, i + 10);
			executor.execute(worker);
		}
		executor.shutdown();
		while (!executor.isTerminated()) {
		}
		System.out.println("Finished all threads");
	}
}

3.- Salida

Una vez que se ejecute el programa se mostrará la siguiente salida:

Current thread pool-1-thread-2 printing value 80
Current thread pool-1-thread-3 printing value 62
Current thread pool-1-thread-2 printing value 62
Current thread pool-1-thread-1 printing value 62
Current thread pool-1-thread-3 printing value 95
Current thread pool-1-thread-2 printing value 95

Como se puede observar existe solo un thread pool que contiene 3 diferentes hilos que imprimen al mismo tiempo los valores correspondientes del arreglo.

Si quieres aprender más sobre hilos recomendamos los siguientes libros:

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com

Introducción a Lambdas en Java 8 Parte 1 en Español


La versión actual de Java es Java 1.8 mejor conocida como Java 8, como toda nueva versión viene con una lista de novedades en el lenguaje, a continuación se explicará como utilizar una de las más importantes, Lambdas !

Introducción

Las expresiones lambda son una de las novedades más importantes de Java 8 y proveen una forma simple de representar un método a través de una expresión. En este post se mostrarán algunos ejemplos simples del funcionamiento de lambda.

Sintaxis de una expresión lambda

Las expresiones lambda permitirán tomar una clase anónima interna y cambiarán de 5 líneas de código a solo una.

Una expresión lambda está compuesta por las siguientes 3 partes:

  • Lista de argumentos     : (int x, int y)
  • Token                                 : ->
  • Cuerpo                               : x + y

El cuerpo puede ser una expresión o un bloque de código el cual simplemente será evaluado y devuelto. A continuación se presentan algunos ejemplos:


(int x, int y) ->  x+y
() -> 55
(String message) ->{System.out.println(message);}

Si se trata de generalizar quedaría del siguiente modo:

(params) -> expression
(params) -> statement
(params) -> { statements }

Ejemplos

1.- Creación de hilos utilizando clases anónimas comunes:

public class LambdaTest {

	public static void main(String[] args) {
		new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 1000; i++) {
System.out.println("I'm a thread " + i);
}
} }).start();
}  }  

Creación de hilos utilizando lambdas:

public class LambdaTest {
public static void main(String[] args) {
new Thread(() -> {
			for (int i = 0; i < 1000; i++) {
		             System.out.println("I'm a thread " + i);
			}
		}).start();
	}
}

En este caso se puede observar como la creación de la clase anónima sobre la interfaz Runnable se simplificó de forma considerable.

2.- Creación de un Comparator utilizando clases anónimas comunes y lambdas:

Paso 1: Creación de la clase de modelo Person.

public class Person {
	private String name;
	private int age;
	private char sex;

	public Person(String name, int age, char sex) {
		super();
		this.name = name;
		this.age = age;
		this.sex = sex;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public char getSex() {
		return sex;
	}

	public void setSex(char sex) {
		this.sex = sex;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + "]";
	}
}

Paso 2: Implementación de un ordenamiento por nombre utilizando clases anónimas:

public class LambdaTest {

	public static void main(String[] args) {
		List<Person> list = new ArrayList<>();
		list.add(new Person("Alex", 28, 'M'));
		list.add(new Person("Wilson", 30, 'M'));
		list.add(new Person("Joyce", 27, 'F'));
		list.add(new Person("Pedro", 26, 'M'));
		list.add(new Person("Juan", 18, 'M'));
		System.out.println(list);
		Collections.sort(list, new Comparator<Person>() {
			@Override
			public int compare(Person p1, Person p2) {
				return p1.getName().compareTo(p2.getName());
			}
		});
		System.out.println(list);
	}
}

Salida:

[Person [name=Alex], Person [name=Wilson], Person [name=Joyce], Person [name=Pedro], Person [name=Juan]]
[Person [name=Alex], Person [name=Joyce], Person [name=Juan], Person [name=Pedro], Person [name=Wilson]]

Paso 3: Implementación de un ordenamiento por nombre utilizando lambdas:


public class LambdaTest {

	public static void main(String[] args) {
		List<Person> list = new ArrayList<>();
		list.add(new Person("Alex", 28, 'M'));
		list.add(new Person("Wilson", 30, 'M'));
		list.add(new Person("Joyce", 27, 'F'));
		list.add(new Person("Pedro", 26, 'M'));
		list.add(new Person("Juan", 18, 'M'));
		System.out.println(list);
		Collections.sort(list, (Person p1, Person p2) -> p1.getName().compareTo(p2.getName()));
		System.out.println(list);
	}
}

Salida:

[Person [name=Alex], Person [name=Wilson], Person [name=Joyce], Person [name=Pedro], Person [name=Juan]]
[Person [name=Alex], Person [name=Joyce], Person [name=Juan], Person [name=Pedro], Person [name=Wilson]]

Como se puede observar en ambos casos la salida es la misma, pero haciendo uso de lambdas es posible escribir código más simple y claro.

3.-Creación de una interfaz propia y su implementación utilizando lambda:

Paso 1: Definición de interfaz a implementar.

interface Calculable {
	double avg(double... numbers);
}

Creando implementación de la interfaz Calculable utilizando lambdas:


public class LambdaTest {

	public static void main(String[] args) {
		Calculable calc = numbers -> {
			double sum = 0.0;
			for (int i = 0; i < numbers.length; i++) {
				sum += numbers[i];
			}
			return sum / numbers.length;
		};
		System.out.println(calc.avg(1,2,3,4,5,6,7,8,9,10));
	}
}

 Como se puede observar dentro del método main se escribe una expresión lambda para implementar el método avg el cual calcula el promedio de un número indefinido de enteros recibidos.

Salida:

5.5

4.-Iterar una colección utilizando Lambdas:

El primer punto a aclarar es que para este ejemplo se utilizará el método void forEach(Consumer<? super T> action) el cuál es un nuevo método incluido en Java 8.

Iteración e impresión de una lista utilizando código anterior a Java 8:

public class LambdaTest {

	public static void main(String[] args) {
		List<Integer>numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
		for (Integer value : numbers) {
			System.out.println(value);
		}
	}
}

Iteración e impresión de una lista utilizando Java 8 sin lambdas:

public class LambdaTest {

	public static void main(String[] args) {
		List<Integer>numbers=Arrays.asList(1,2,3,4,5,6,7,8,9,10);
		numbers.forEach(new Consumer<Integer>() {
			@Override
			public void accept(Integer t) {
				System.out.println(t);
			}
		});
	}
}

Como se puede observar se hace uso del método forEach el cuál recibe un objeto que implemente la interfaz Consumer, es importante mencionar que tanto el método forEach como la interfaz Consumer fueron agregadas desde Java 8

Iteración e impresión de una lista utilizando Java 8 con lambdas:

import java.util.Arrays;
import java.util.List;

public class LambdaTest {

	public static void main(String[] args) {
		List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
		numbers.forEach((Integer t) -> {
			System.out.println(t);
		});
	}
}

En próximos posts se explicará como hacer programación funcional en Java y más novedades de Java 8.

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com