Clase Thread Y Interfaz Runneable
Clase Thread y Interfaz Runneable
Java proporciona dos formas principales para crear y ejecutar hilos:
- Clase
Thread: Extendiendo la claseThready sobrescribiendo su métodorun(). - Interfaz
Runnable: Implementando la interfazRunnabley definiendo la lógica del hilo en el métodorun().
Ambos enfoques logran lo mismo: definir tareas que se ejecutarán en un hilo independiente, pero tienen diferencias importantes en su uso y en el diseño del programa.
| Aspecto | Clase Thread |
Interfaz Runnable |
|---|---|---|
| Extensión de clases | Debes extender la clase Thread, limitando la herencia de otras clases. |
Implementa Runnable, permitiendo extender otras clases. |
| Acoplamiento | Lógica de negocio y control de hilo están acoplados. | Lógica de negocio y control de hilo están separados. |
| Reutilización | Menos flexible, difícil de reutilizar la lógica del hilo. | Más flexible, puede ejecutarse en diferentes entornos. |
| Uso recomendado | Útil para tareas simples donde el control del hilo no requiere separación. | Recomendado para aplicaciones más complejas o modulares. |
1. Clase Thread
La clase Thread representa un hilo en Java. Para usarla, extiendes la clase y sobrescribes el método run() con la lógica que debe ejecutarse en el hilo.
Ejemplo Básico
class MiHilo extends Thread {
@Override
public void run() {
System.out.println("Hilo en ejecución: " + getName());
}
}
public class EjemploThread {
public static void main(String[] args) {
MiHilo hilo1 = new MiHilo();
MiHilo hilo2 = new MiHilo();
hilo1.start(); // Comienza la ejecución del hilo
hilo2.start();
}
}
Salida esperada:
Hilo en ejecución: Thread-0
Hilo en ejecución: Thread-1
Ventajas y Desventajas
- Ventaja: Más sencillo de implementar para casos donde no se necesita mucha modularidad.
- Desventaja: Al extender
Thread, no puedes heredar de otras clases, lo que limita la flexibilidad.
2. Interfaz Runnable
La interfaz Runnable separa la lógica de la tarea del control del hilo. Es una interfaz funcional con un único método: run().
Ejemplo Básico
class MiRunnable implements Runnable {
@Override
public void run() {
System.out.println("Hilo en ejecución: " + Thread.currentThread().getName());
}
}
public class EjemploRunnable {
public static void main(String[] args) {
Thread hilo1 = new Thread(new MiRunnable());
Thread hilo2 = new Thread(new MiRunnable());
hilo1.start();
hilo2.start();
}
}
Salida esperada:
Hilo en ejecución: Thread-0
Hilo en ejecución: Thread-1
Ventajas y Desventajas
- Ventaja: Más flexible porque puedes usar la misma clase en diferentes escenarios y ejecutar la lógica en diferentes contextos.
- Desventaja: Requiere más líneas de código si solo necesitas algo sencillo.
3. Usando Lambdas con Runnable
Desde Java 8, puedes usar expresiones lambda para definir la lógica de un hilo de manera más compacta.
Ejemplo
public class EjemploLambdaRunnable {
public static void main(String[] args) {
Thread hilo = new Thread(() -> System.out.println("Hilo ejecutado con Lambda"));
hilo.start();
}
}
Salida esperada:
Hilo ejecutado con Lambda
4. Comparación Práctica: Thread vs Runnable
Caso: Ejecutar Diferentes Tareas
Con Thread: Cada tarea requiere una nueva clase.
class Tarea1 extends Thread {
@Override
public void run() {
System.out.println("Ejecutando Tarea 1");
}
}
class Tarea2 extends Thread {
@Override
public void run() {
System.out.println("Ejecutando Tarea 2");
}
}
public class EjemploThreadTareas {
public static void main(String[] args) {
new Tarea1().start();
new Tarea2().start();
}
}
Con Runnable: Puedes reusar la lógica fácilmente.
public class EjemploRunnableTareas {
public static void main(String[] args) {
Runnable tarea1 = () -> System.out.println("Ejecutando Tarea 1");
Runnable tarea2 = () -> System.out.println("Ejecutando Tarea 2");
new Thread(tarea1).start();
new Thread(tarea2).start();
}
}
5. Ejemplo Avanzado: Compartir Recursos
Cuando múltiples hilos acceden al mismo recurso, usar Runnable permite una mejor separación.
Ejemplo con Runnable y Sincronización
class ContadorCompartido implements Runnable {
private int cuenta = 0;
// Using sincronized
@Override
public synchronized void run() {
for (int i = 0; i < 5; i++) {
cuenta++;
System.out.println(Thread.currentThread().getName() + " - Cuenta: " + cuenta);
}
}
}
public class EjemploRunnableCompartido {
public static void main(String[] args) {
ContadorCompartido tarea = new ContadorCompartido();
Thread hilo1 = new Thread(tarea);
Thread hilo2 = new Thread(tarea);
hilo1.start();
hilo2.start();
}
}
Salida esperada:
Thread-0 - Cuenta: 1
Thread-0 - Cuenta: 2
Thread-1 - Cuenta: 3
Thread-0 - Cuenta: 4
Thread-1 - Cuenta: 5