Skip to content

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.

package java.util.concurrent;

public interface ThreadFactory {
    Thread newThread(Runnable r);
}

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: