11 ThreadFactory¶
Crear hilos mediante una fábrica de hilos¶
Uno de los patrones de diseño más usados en el mundo de la programación orientada a objetos es el conocido como fábrica de objetos (factory pattern, en inglés). Un objeto Fábrica tiene la misión de crear otros objetos de uno o varias clases. Cuando queremos crear un objeto de una de esas clases usaremos un método de la fábrica en vez de usar directamente el operador de instanciación new
.
El hecho de centralizar la creación de los objetos tiene algunas ventajas:
- Es fácil cambiar la clase de los objetos creados o la forma en la que se crean.
- Es sencillo limitar el número de objetos creados que usen un mismo recurso limitado. Por ejemplo, limitar que sólo puedan crearse
n
objetos de una cierta clase. - Nos facilita la generación de datos estadísticos sobre la creación de los objetos.
Java nos proporciona la interfaz ThreadFactory
para implementar una fábrica de objetos Thread
, es decir, una fábrica de hilos.
La interfaz ThreadFactory
posee un sólo método llamado newThread()
, que deberemos implementar forzosamente. Este método recibe el objeto Runnable
que queremos que ejecute el hilo y retorna el objeto Thread
correspondiente al hilo creado.
Si utilizamos una fábrica de hilos, lo lógico es asegurarnos de que todos los hilos de nuestro programa son creados a través de dicha fábrica.
Proyecto ThreadFactory¶
En el siguiente ejemplo crearemos un fábrica de hilos que construye los hilos con un nombre base personalizado y almacena un registro de la creación de hilos. Al terminar de ejecutarse todos los hilos se muestra el registro de la fábrica de hilos.
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) {
final MyThreadFactory threadFactory = new MyThreadFactory("MyThreadFactory");
ArrayList<Thread> threads = new ArrayList<>();
for (int i = 0; i < 3; i++) {
Thread thread = threadFactory.newThread(new Task());
threads.add(thread);
thread.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException exception) {
return;
}
}
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException exception) {
return;
}
}
System.out.printf("\n\nMyThreadFactory Log\n\n%s", threadFactory.getLog());
}
}
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
public class Task implements Runnable {
private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
@Override
public void run() {
try {
System.out.printf("%s -> %s started\n",
LocalTime.now().format(dateTimeFormatter), Thread.currentThread().getName());
// Simulate task working.
TimeUnit.SECONDS.sleep(ThreadLocalRandom.current().nextInt(5) + 1);
System.out.printf("%s -> %s finished\n",
LocalTime.now().format(dateTimeFormatter), Thread.currentThread().getName());
} catch (InterruptedException ignored) {
}
}
}
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.concurrent.ThreadFactory;
public class MyThreadFactory implements ThreadFactory {
private int count = 0;
private final String baseName;
private final ArrayList<String> log = new ArrayList<>();
private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
public MyThreadFactory(String baseName) {
this.baseName = baseName;
}
@Override
public Thread newThread(Runnable runnable) {
Thread thread = new Thread(runnable, baseName + "-" + count++);
log.add(LocalTime.now().format(dateTimeFormatter) + " -> " + thread.getName() + " created");
return thread;
}
public String getLog() {
return String.join("\n", log);
}
}
Si ejecutamos el programa veremos que los hilos se crean usando la factoría y que se guarda un registro con la hora de creación de los hilos: