Multihilo en Java explicado: Conceptos, ciclo de vida y ejemplos de código prácticos
Las aplicaciones Java a menudo necesitan realizar múltiples tareas simultáneamente. Este tutorial te guía a través de ejecución mono-hilo versus multi-hilo, el ciclo de vida de un hilo, técnicas de sincronización y ejemplos de código prácticos que ilustran cada concepto.
¿Qué es un hilo único (Single Thread)?
Un hilo único en Java es la unidad más pequeña de ejecución. El runtime de Java crea un hilo de usuario cuando la aplicación inicia, y puedes añadir hilos de usuario adicionales o hilos daemon según sea necesario. Los hilos daemon se ejecutan en segundo plano y no impiden que la JVM termine.
Ejemplo de un hilo único:
package demotest;
public class GuruThread {
public static void main(String[] args) {
System.out.println("Hilo Único");
}
}
Ventajas de la ejecución mono-hilo:
- Sobrecarga mínima — solo se mantiene un contexto de ejecución.
- Depuración y mantenimiento simplificados.
¿Qué es Multihilo (Multithreading) en Java?
El multihilo permite que dos o más hilos se ejecuten concurrentemente, maximizando el uso de CPU. Los hilos comparten el mismo espacio de memoria, por lo que los cambios de contexto son rápidos y el uso de memoria se mantiene bajo.
Ejemplo de creación de dos hilos concurrentes:
package demotest;
public class GuruThread1 implements Runnable {
public static void main(String[] args) {
Thread guruThread1 = new Thread("Guru1");
Thread guruThread2 = new Thread("Guru2");
guruThread1.start();
guruThread2.start();
System.out.println("Los nombres de los hilos son:");
System.out.println(guruThread1.getName());
System.out.println(guruThread2.getName());
}
@Override
public void run() {
// Lógica del hilo va aquí
}
}
Beneficios del multihilo:
- UI no bloqueante y procesamiento en segundo plano.
- Resiliencia — una excepción en un hilo no detiene a los demás.
Ciclo de vida de un hilo en Java
El ciclo de vida del hilo consta de cinco estados distintos:
- Nuevo (New) – El hilo se instancia pero no se inicia.
- Ejecutable (Runnable) – El hilo ha sido iniciado y está listo para ejecución.
- En ejecución (Running) – El hilo está ejecutándose activamente.
- En espera (Waiting) – El hilo está suspendido hasta que ocurre un evento específico.
- Muerto (Dead) – El hilo ha terminado su ejecución.
Métodos clave de Thread
| Método | Descripción |
|---|---|
| start() | Inicia la ejecución del hilo; la JVM llama a run(). |
| sleep(long milisegundos) | Pausa el hilo actual durante la duración especificada. |
| getName() | Devuelve el nombre del hilo. |
| setPriority(int nuevaPrioridad) | Ajusta la prioridad del hilo (1–10). |
| yield() | Sugiere al planificador pausar el hilo actual. |
Ejemplo práctico de hilo
A continuación se muestra un ejemplo conciso que demuestra creación de hilos, ajuste de prioridad y sleep.
package demotest;
public class ThreadExample1 implements Runnable {
@Override
public void run() {
// Trabajo del hilo aquí
}
public static void main(String[] args) {
Thread guruThread1 = new Thread();
guruThread1.start();
try {
Thread.sleep(1000); // pausa 1 segundo
} catch (InterruptedException e) {
e.printStackTrace();
}
guruThread1.setPriority(1);
System.out.println(guruThread1.getPriority());
System.out.println("Hilo en ejecución");
}
}
Ejemplo de salida:
Sincronización de hilos
Cuando múltiples hilos acceden a recursos compartidos, la sincronización asegura consistencia de datos. En Java, puedes envolver secciones críticas con la palabra clave synchronized, garantizando acceso exclusivo.
synchronized(objeto) {
// bloque sincronizado
}
Ejemplo avanzado de multihilo
A continuación se muestra un ejemplo más elaborado que crea dos hilos, cada uno imprimiendo su nombre y un contador con un retraso de un segundo.
package demotest;
public class GuruThread2 {
public static void main(String[] args) {
GuruThread3 threadGuru1 = new GuruThread3("guru1");
threadGuru1.start();
GuruThread3 threadGuru2 = new GuruThread3("guru2");
threadGuru2.start();
}
}
class GuruThread3 implements Runnable {
private Thread guruthread;
private String guruname;
GuruThread3(String name) {
this.guruname = name;
}
@Override
public void run() {
System.out.println("Hilo ejecutándose " + guruname);
for (int i = 0; i < 4; i++) {
System.out.println(i);
System.out.println(guruname);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Hilo ha sido interrumpido");
}
}
}
public void start() {
System.out.println("Hilo iniciado");
if (guruthread == null) {
guruthread = new Thread(this, guruname);
guruthread.start();
}
}
}
Salida típica (ilustrada en la imagen adjunta):
Conclusión
- El multihilo libera a la aplicación de llamadas bloqueantes y permite operaciones concurrentes.
- El ciclo de vida del hilo —Nuevo, Ejecutable, En ejecución, En espera, Muerto— define los estados por los que pasa un hilo.
- La sincronización es esencial cuando los hilos comparten datos, previniendo condiciones de carrera.
- Ejemplos de código prácticos refuerzan la comprensión de creación de hilos, gestión del ciclo de vida y sincronización.
Java
- Funciones en C++ Explicadas con Ejemplos de Código Prácticos
- Dominando Colecciones en C#: Tutorial Práctico con Ejemplos del Mundo Real
- Dominar la multihilo en C++: Programación concurrente eficiente
- Java Hello World: Tu Primer Programa
- Dominando Java String.indexOf(): Localizar subcadenas y ejemplos prácticos
- Entendiendo Java String.charAt(): Sintaxis, tipo de retorno, excepciones y ejemplo práctico
- Dominando el método compareTo() de Java String: Sintaxis, casos de uso y ejemplos prácticos
- Sobrecarga de constructores en Java – Explicado con ejemplos de código prácticos
- Programa en Java para Determinar si un Número es Primo
- Algoritmo Insertion Sort en Java: Ejemplo Claro y Guía Paso a Paso
- Selection Sort en Java: Ejemplo Paso a Paso y Código Completo