Ejemplos

Ejemplo 5: Uso de Hilos con Thread y Runnable

Ejemplo de cómo usar hilos en Java usando Thread y Runnable, además de las funciones sleep y join e interrupciones.

En este ejemplo, vamos a crear un programa en Java que utiliza hilos para ejecutar tareas concurrentes. Utilizaremos la clase Thread y la interfaz Runnable para crear y manejar los hilos. Además, veremos cómo usar las funciones sleep, join e interrupciones para controlar la ejecución de los hilos.

Descripción del Problema

Supongamos que queremos simular un proceso de descarga de archivos. Cada archivo se descargará en un hilo separado, y queremos que el programa principal espere a que todas las descargas se completen antes de finalizar.

Para resolver este problema, crearemos una clase DownloadTask que implementa la interfaz Runnable. Esta clase representará la tarea de descargar un archivo. Luego, crearemos una clase que manejará la creación y ejecución de los hilos para cada tarea de descarga. Posteriormente, utilizaremos las funciones sleep para simular el tiempo de descarga, join para esperar a que los hilos terminen su ejecución y interrupt para manejar posibles interrupciones. Para finalizar, implementaremos un método para mostrar el progreso de las descargas.

Código de Resolución

Antes de plantear el código, es importante mencionar que este ejemplo se centra en la creación y manejo de hilos en Java, por lo que no se implementará una lógica real de descarga de archivos, sino que se simulará el proceso con tiempos de espera.

Así mismo partiremos de la siguiente estructura de clases:

.
└── concurrencia/
    └── src/
        └── app/
            └── concurrencia/
                ├── entities/
                │   ├── DownloadTask.java
                │   └── ThreadManager.java
                └── launch/
                    └── Main.java

Paso 1: Crear la clase DownloadTask

Para empezar, crearemos la clase DownloadTask que implementa Runnable. Esta clase tendrá un constructor que recibe el nombre del archivo a descargar y un método run que simula la descarga.

package app.concurrencia.entities;

/**
 * Clase que representa una tarea de descarga de un archivo.
 */
public class DownloadTask implements Runnable {
    /**
     * Nombre del archivo a descargar.
     */
    private String fileName;

    /**
     * Constructor de la clase DownloadTask.
     * 
     * @param fileName Nombre del archivo a descargar.
     */
    public DownloadTask(String fileName) {
        this.fileName = fileName;
    }

    /**
     * Función que simula la descarga del archivo. Imprime el nombre del archivo que se está descargando, luego espera un tiempo aleatorio para simular el proceso de descarga y finalmente imprime un mensaje indicando que la descarga ha sido completada. Si el hilo es interrumpido durante la descarga, se captura la excepción y se imprime un mensaje indicando que la descarga ha sido interrumpida.
     */
    @Override
    public void run() {
        try {
            IO.println("Descargando: " + fileName);
            // Simular el tiempo de descarga
            Thread.sleep((long) (Math.random() * 5000));
            IO.println("Descarga completada: " + fileName);
        } catch (InterruptedException e) {
            IO.println("Descarga interrumpida: " + fileName);
        }
    }
}

Paso 2: Crear la clase ThreadManager

A continuación, crearemos la clase ThreadManager que se encargará de crear y manejar los hilos para cada tarea de descarga. Esta clase tendrá un método para iniciar las descargas y otro para esperar a que todas las descargas se completen.

package app.concurrencia.entities;

import java.util.ArrayList;
import java.util.List;

/**
 * Clase que maneja la creación y ejecución de hilos para tareas de descarga.
 */
public class ThreadManager {
    /**
     * Lista de hilos que representan las tareas de descarga.
     */
    private List<Thread> threads;

    /**
     * Constructor de la clase ThreadManager. Inicializa la lista de hilos.
     */
    public ThreadManager() {
        threads = new ArrayList<>();
    }

    /**
     * Función para iniciar las descargas. Crea un hilo para cada tarea de descarga y lo inicia.
     * 
     * @param fileNames Lista de nombres de archivos a descargar.
     */
    public void startDownloads(List<String> fileNames) {
        for (String fileName : fileNames) {
            Thread thread = new Thread(new DownloadTask(fileName));
            threads.add(thread);
            thread.start();
        }
    }

    /**
     * Función para esperar a que todas las descargas se completen. Utiliza la función join para esperar a que cada hilo termine su ejecución.
     */
    public void waitForDownloads() {
        for (Thread thread : threads) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                IO.println("Esperando a que las descargas se completen ha sido interrumpido.");
            }
        }
    }
}

Paso 3: Crear la clase Main

Finalmente, crearemos la clase Main que será el punto de entrada del programa. En esta clase, crearemos una instancia de ThreadManager, iniciaremos las descargas y esperaremos a que todas las descargas se completen.

package app.concurrencia.launch;

import app.concurrencia.entities.ThreadManager;
import java.util.Arrays;
import java.util.List;

/**
 * Clase principal del programa que simula la descarga de archivos utilizando hilos.
 */
public class Main {
    void main() {
        // Lista de archivos a descargar
        List<String> fileNames = Arrays.asList("archivo1.txt", "archivo2.txt", "archivo3.txt");

        // Crear una instancia de ThreadManager
        ThreadManager threadManager = new ThreadManager();

        // Iniciar las descargas
        threadManager.startDownloads(fileNames);

        // Esperar a que todas las descargas se completen
        threadManager.waitForDownloads();

        IO.println("Todas las descargas han sido completadas.");
    }
}

Salida Esperada

Al ejecutar el programa, se espera ver una salida similar a la siguiente, aunque el orden de las descargas puede variar debido a la naturaleza concurrente de los hilos:

Descargando: archivo1.txt
Descargando: archivo2.txt
Descargando: archivo3.txt
Descarga completada: archivo2.txt
Descarga completada: archivo1.txt
Descarga completada: archivo3.txt
Todas las descargas han sido completadas.

Notarás que puedes ver que las descargas se inician al mismo tiempo, pero el orden de finalización puede variar debido a los tiempos de descarga simulados. Además, si interrumpes el programa mientras las descargas están en progreso, podrías ver mensajes indicando que las descargas han sido interrumpidas.

Conclusión

En este ejemplo, hemos visto cómo utilizar hilos en Java para ejecutar tareas concurrentes. Hemos creado una clase DownloadTask que implementa Runnable para simular la descarga de archivos, y una clase ThreadManager para manejar la creación y ejecución de los hilos. Además, hemos utilizado las funciones sleep, join e interrupciones para controlar la ejecución de los hilos. Este ejemplo demuestra cómo la concurrencia puede ser manejada en Java utilizando hilos, lo que permite ejecutar múltiples tareas al mismo tiempo de manera eficiente.

Copyright Jesús Aurelio Castro Magaña © 2026