Crear un hilo en Java

La clase que nos importa aquí es java.lang.Thread, y podemos crear hilos de dos formas: extendiendo la clase y sobreescribiendo el método run(), o bien usando un Runnable. Lo importante luego es utilizar el método start() para poner el hilo en ejecución.

En el lenguaje de programación Java, para crear un hilo se puede utilizar la clase Thread, que forma parte de la biblioteca estándar de Java y del propio paquete java.lang.

Para definir un hilo tenemos dos formas de hacer esto. O bien podríamos extender la clase Thread, o bien podríamos usar un Runnable.

Extendiendo de Thread

Puedes crear un hilo en Java si fabricas una subclase que extiende de la clase Thread. Una vez hagas esto, podrás sobreescribir el método run(), que es el método que tiene la clase Thread para lanzar el programa que tiene que ejecutarse cuando se inicia un hilo.

public class MiHilo extends Thread {
  @Override
  public void run() {
    System.out.println("Formo parte de mi hilo");
  }
}

Una vez que hayas definido tu hilo, puedes crear una instancia del mismo como quien instancia cualquier otra clase que contenga la lógica de una acción. Incluso, si le pusieses un constructor a tu clase y los guardases como atributos, podrías utilizarlos desde el método run().

MiHilo hilo = new MiHilo();

// En este otro caso, la clase MiOtroHilo también extiende
// de Thread pero le he puesto un constructor propio.
MiOtroHilo ejemplo = new MiOtroHilo(20);

Cuando instancias un hilo, su código no se ejecuta. Este dato es importante. No por instanciar el hilo se va a correr automáticamente. Cuando instancies un hilo, su estado será NEW, pero ese estado no indica que esté listo para ejecutarse.

Para iniciar ese hilo puedes habilitarlo usando el método start(). No te confundas con esto: no debes llamar al método run() de una instancia de Thread. A pesar de que el método que sobreescribes es el run(), y a pesar de que ese método es público, si llamases al método run() todo lo que harías es ejecutar ese código en el mismo hilo. El método start() es el que cambia el estado de un hilo para marcarlo como listo para ejecutar, y eso provoca que el código de run() eventualmente se ejecute en otro hilo de sistema independiente.

hilo.start();
System.out.println("Hola mundo");

Eventualmente producirá la salida esperada, que son los dos prints. No tienen por qué hacerse en el mismo orden, y de hecho lo más probable es que, pese a que invocamos a start() antes de imprimir ese "Hola mundo", su mensaje de print aparezca después.

Hola mundo
Formo parte de mi hilo

Implementando un Runnable

El problema de extender de Thread para fabricar hilos es que entonces tu clase se acopla demasiado a la clase Thread, lo que puede dificultar encajar la clase en algunos diagramas de clases.

Una solución más neutra es utilizar la interfaz Runnable. Esta interfaz es una interfaz de tipo funcional que expone un único método:

public interface Runnable {
  void run();
}

Esta interfaz se usa también en otras partes del lenguaje de programación Java. En el caso de los hilos, es posible directamente instanciar un java.lang.Thread utilizando un constructor especial que acepta como parámetro un Runnable. De este modo, en vez de extender la clase Thread, lo que hacemos es definir el código en un Runnable, y luego asociarlo con una instancia genérica de Thread.

En este caso, el método run() del Thread lo que hará es simplemente delegar y llamar al método run() del Runnable que le pasamos como constructor.

Otras estructuras concurrentes del lenguaje de programación Java también aceptan Runnable para definir la pieza de código que se debe ejecutar concurrentemente. En conclusión, es preferible fabricar implementaciones de Runnable a extender de Thread, ya que así si en el futuro tienes que cambiar tu Thread por otra cosa, como por ejemplo un Future, es más fácil de cambiar de una clase a otra si ambas aceptan un Runnable que si tienes que modificar de qué clase extiende tu subclase.

En cuanto a la forma de utilizar un Runnable, es bastante asumible. Primero tenemos que fabricar la implementación de la clase:

public class UnRunnable implements Runnable {
  @Override
  public void run() {
    System.out.println("Soy un Runnable");
  }
}

Y luego fabricamos ese hilo pasándole como parámetro una instancia de Runnable, para que el método run() de Thread llame al método run() del Runnable asociado:

var miRunnable = new UnRunnable();
var thread = new Thread(miRunnable);

// Esta es otra forma de instanciar el hilo:
var thread2 = new Thread(new UnRunnable());

Getters de interés de un hilo

Cuando tengas una referencia a un Thread, vas a poder utilizar sus getters para poder inferir información sobre el mismo. Por ejemplo:

  • getName(): te va a dar el nombre que tenga asignado el hilo.
  • getState(): te va a dar un valor de tipo State, que es el enumerado para identificar el estado del hilo: NEW, RUNNING, WAITING...
  • getPriority(): te va a dar un valor numérico que representa la prioridad del hilo en una escala de la menos prioritaria a la más prioritaria.
Lista de reproducción
  1. 1
    ¿Qué es la concurrencia?
    8 minutos
  2. 2
    ¿Qué es un hilo?
    5 minutos
  3. 3
    Crear un hilo en Java
    10 minutos
  4. 4
    Interrupción de hilos
    10 minutos
  5. 5
    Cómo usar Thread.join
    14 minutos
  6. 6
    Corrupción de memoria
    8 minutos
  7. 7
    Monitores y synchronized
    10 minutos
  8. 8
    Bloque synchronized
    12 minutos
  9. 9
    Preguntas típicas sobre synchronized en Java
    8 minutos
  10. 10
    Interbloqueos, synchronized y el problema de la cena de los filósofos
    13 minutos
  11. 11
    Introducción a Executor en Java
    11 minutos
  12. 12
    Introducción al uso de ExecutorService en Java
    14 minutos
  13. 13
    Introducción a Thread Pools en Java
    10 minutos
  14. 14
    Cómo crear Thread Pools en Java
    11 minutos
  15. 15
    ¿Cómo funcionan wait() y notify()?
    10 minutos
  16. 16
    Ejemplo de wait() y notify() en Java
    9 minutos
  17. 17
    La palabra clave volatile
    8 minutos
  18. 18
    Cómo usar Future
    8 minutos
  19. 19
    Variables atómicas
    7 minutos