Interfaz ThreadFactory en Java con ejemplos

La interfaz ThreadFactory definida en el paquete java.util.concurrent se basa en el patrón de diseño de fábrica . Como su nombre indica, se utiliza para crear nuevos hilos bajo demanda. Los hilos se pueden crear de dos maneras:

1. Crear una clase que extienda la clase Thread y luego crear sus objetos.

Java

import java.io.*;
 
class GFG {
   
    public static void main(String[] args)
    {
        // Creating a thread
        Thread thread = new CustomThread();
        thread.start(); // Starting execution of the created
                        // thread
    }
}
 
// Creating a class that extends the Thread class
class CustomThread extends Thread {
    @Override public void run()
    {
        System.out.println("This is a thread");
    }
}
Producción

This is a thread

2. Crear una clase que implemente la interfaz Runnable y luego usar su objeto para crear subprocesos.

Java

/*package whatever //do not write package name here */
 
import java.io.*;
 
class GFG {
    public static void main(String[] args)
    {
        // Creating a Runnable object
        Runnable task = new Task();
        // Creating a thread using the Runnable object
        Thread thread = new Thread(task);
        // Starting the execution of the created thread
        thread.start();
    }
}
 
class Task implements Runnable {
    @Override public void run()
    {
        System.out.println("This is a thread");
    }
}
Producción

This is a thread

Sin embargo, ThreadFactory es otra opción para crear nuevos hilos. Esta interfaz proporciona un método de fábrica que crea y devuelve nuevos subprocesos cuando se le llama. Este método de fábrica toma un objeto Runnable como argumento y crea un nuevo hilo usándolo.

La jerarquía de ThreadFactory

java.util.concurrent
    ↳ Interface ThreadFactory

Implementación de la interfaz ThreadFactory

 Dado que ThreadFactory es una interfaz, el método de fábrica definido en su interior debe implementarse primero para poder usarse. Aquí está la implementación más simple de la interfaz ThreadFactory:  

Java

import java.util.concurrent.ThreadFactory;
import java.io.*;
 
class CustomThreadFactory implements ThreadFactory {
 
    // newThread is a factory method
    // provided by ThreadFactory
    public Thread newThread(Runnable command)
    {
        return new Thread(command);
    }
}

Ahora, podemos crear objetos de la clase CustomThreadFactory y usar su método newThread(Runnable command) para crear nuevos subprocesos a pedido. En la implementación anterior, el método newThread simplemente crea un nuevo hilo llamando al constructor Thread que toma un comando Runnable como parámetro.

Hay muchas clases (como ScheduledThreadPoolExecutor , ThreadPoolExecutor , etc.) que usan fábricas de subprocesos para crear nuevos subprocesos cuando es necesario. Esas clases tienen constructores que aceptan ThreadFactory como argumento. Si no se proporciona ningún ThreadFactory personalizado, entonces usan la implementación predeterminada de la interfaz ThreadFactory. 

La clase Executors en el paquete java.util.concurrent proporciona el método estático Executors.defaultThreadFactory() que devuelve una implementación predeterminada de la interfaz ThreadFactory.

Ejemplo: El siguiente código de ejemplo muestra la interfaz ThreadFactory.

Java

// Java code to demonstrate ThreadFactory interface
 
import java.util.concurrent.ThreadFactory;
import java.io.*;
import java.util.ArrayList;
 
class ThreadFactoryExample {
    public static void main(String[] args)
    {
        // Creating a CustomThreadFactory object
        CustomThreadFactory threadFactory
            = new CustomThreadFactory();
 
        // Creating Runnable objects using the lambda
        // expression
        Runnable command1 = ()
            -> System.out.println("Command 1 executed");
        Runnable command2 = ()
            -> System.out.println("Command 2 executed");
        Runnable command3 = ()
            -> System.out.println("Command 3 executed");
        Runnable command4 = ()
            -> System.out.println("Command 4 executed");
        Runnable command5 = ()
            -> System.out.println("Command 5 executed");
 
        // Putting the commands in an ArrayList
        ArrayList<Runnable> array = new ArrayList<>(5);
        array.add(command1);
        array.add(command2);
        array.add(command3);
        array.add(command4);
        array.add(command5);
 
        // creating threads and running them
        for (Runnable command : array) {
            threadFactory.newThread(command).start();
        }
 
        // print the thread count
        System.out.println(
            "Total number of threads created using CustomThreadFactory = "
            + threadFactory.getCount());
    }
}
 
// ThreadFactory class
class CustomThreadFactory implements ThreadFactory {
 
    // stores the thread count
    private int count = 0;
 
    // returns the thread count
    public int getCount() { return count; }
 
    // Factory method
    @Override
      public Thread newThread(Runnable command)
    {
        count++;
        return new Thread(command);
    }
}
Producción

Command 1 executed
Command 2 executed
Command 4 executed
Command 3 executed
Command 5 executed
Total number of threads created using CustomThreadFactory = 5

¿Por qué usar ThreadFactory?

En el ejemplo anterior, el método de fábrica newThread(Runnable) finalmente crea un nuevo hilo usando el comando Runnable dado. Entonces, ¿por qué usar ThreadFactory? Podríamos crear subprocesos directamente a partir de los comandos Runnable llamando al constructor Thread que hicimos en el método newThread(Runnable). Aquí hay algunas razones,

  • Podemos dar a los subprocesos nombres personalizados más significativos. Ayuda a analizar sus propósitos y cómo funcionan.
  • Podemos tener estadísticas sobre los hilos creados, como el recuento de hilos y otros detalles. Podemos restringir la creación de nuevos hilos en función de las estadísticas.
  • Podemos establecer el estado del demonio de los hilos.
  • Podemos establecer la prioridad del hilo.
  • Podemos tener todas las características confinadas en una clase.

Fábrica de subprocesos predeterminada

Es la fábrica de subprocesos predeterminada implementada por el método estático Executors.defaultThreadFactory() . Muchas clases utilizan esta ThreadFactory predeterminada (como ScheduledThreadPoolExecutor , ThreadPoolExecutor , etc.) cuando no reciben ninguna ThreadFactory personalizada. Esas clases crean nuevos subprocesos utilizando ThreadFactory predeterminado. Este ThreadFactory predeterminado crea todos los subprocesos nuevos en el mismo ThreadGroup (un ThreadGroup representa un grupo de subprocesos). Todos los subprocesos nuevos creados no son daemon con la prioridad establecida en el valor más pequeño de Thread.NORM_PRIORITY y la prioridad máxima permitida en ThreadGroup. Los subprocesos creados por este ThreadFactory predeterminado reciben nombres en forma de pool-N-thread-M(Como ejemplos, grupo-1-hilo-1, grupo-1-hilo-2, grupo-2-hilo-1, etc.) donde N es el número de secuencia de esta fábrica y M es el número de secuencia de los hilos creados por esta fábrica.

Ejemplo: El siguiente ejemplo demuestra cómo se puede usar ThreadFactory predeterminado. 

Java

// Java program to demonstrate default
// ThreadFactory
 
import java.io.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
 
class DefaultThreadFactoryExample {
    public static void main(String[] args)
    {
        // Default ThreadFactory
        ThreadFactory threadFactory
            = Executors.defaultThreadFactory();
 
        for (int i = 1; i < 10; i++) {
 
            // Creating new threads with the default
            // ThreadFactory
            Thread thread
                = threadFactory.newThread(new Command());
 
            // print the thread names
            System.out.println(
                "Name given by threadFactory = "
                + thread.getName());
 
            // run the thread
            thread.start();
        }
    }
}
 
class Command implements Runnable {
 
    @Override public void run()
    {
        // Run some code
    }
}
Producción

Name given by threadFactory = pool-1-thread-1
Name given by threadFactory = pool-1-thread-2
Name given by threadFactory = pool-1-thread-3
Name given by threadFactory = pool-1-thread-4
Name given by threadFactory = pool-1-thread-5
Name given by threadFactory = pool-1-thread-6
Name given by threadFactory = pool-1-thread-7
Name given by threadFactory = pool-1-thread-8
Name given by threadFactory = pool-1-thread-9

Tenga en cuenta los nombres de los subprocesos dados por defecto ThreadFactory. Ha creado 9 subprocesos y todos los subprocesos están en el mismo ThreadGroup. Todos los subprocesos se crean utilizando la misma fábrica de subprocesos (por lo que los nombres de los subprocesos tienen la forma de pool -1 -thread-M ).

Ejemplo: 

Java

// Java program to demonstrate ThreadFactory
// using default implementation
 
import java.io.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
 
class DefaultThreadFactoryExample {
    public static void main(String[] args)
    {
 
        for (int i = 1; i < 10; i++) {
 
            // Default ThreadFactory
            ThreadFactory threadFactory
                = Executors.defaultThreadFactory();
 
            // Creating new threads with the default
            // ThreadFactory
            Thread thread
                = threadFactory.newThread(new Command());
 
            // print the thread name
            System.out.println(
                "Name given by threadFactory = "
                + thread.getName());
 
            // start the thread
            thread.start();
        }
    }
}
 
class Command implements Runnable {
    @Override public void run()
    {
        // Run some code
    }
}
Producción

Name given by threadFactory = pool-1-thread-1
Name given by threadFactory = pool-2-thread-1
Name given by threadFactory = pool-3-thread-1
Name given by threadFactory = pool-4-thread-1
Name given by threadFactory = pool-5-thread-1
Name given by threadFactory = pool-6-thread-1
Name given by threadFactory = pool-7-thread-1
Name given by threadFactory = pool-8-thread-1
Name given by threadFactory = pool-9-thread-1

Aquí, hemos utilizado 9 ThreadFactories predeterminados diferentes (¡en cada bucle estamos creando uno nuevo!). Entonces, cada subproceso está en un grupo de subprocesos diferente y, por lo tanto, los subprocesos reciben un nombre en forma de pool-N-thread-1 .

La implementación predeterminada de ThreadFactory crea subprocesos que no son demonios con prioridad normal y da nombres en forma de pool-N-thread-M que no contiene información sobre cómo funcionan y qué hacen. Esto crea muchos problemas en la depuración y otros propósitos importantes. Sin embargo, este problema se puede resolver utilizando un ThreadFactory personalizado que puede dar nombres más significativos a los subprocesos y puede establecer el daemon y los estados de prioridad.

Métodos de ThreadFactory

MÉTODO

DESCRIPCIÓN

newThread​(ejecutable r) Construye un hilo nuevo.

Publicación traducida automáticamente

Artículo escrito por samufo y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *