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 tipoState, 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.