Multitarea e Hilos en Java con ejemplos (Thread & Runnable)


El proyecto de este post lo puedes descargar pulsando AQUI.

En esta entrada vamos a ver las diferentes maneras de como trabajar con Threads en Java (o hilos en español). Sino tienes muy claro el concepto de la multitarea te recomendamos que te leas primero la entrada de Multitaréa e Hilos, fácil y muchas ventajas aunque en esta entrada también veremos (en menor detalle) los conceptos y las ventajas de la multitarea.

En esencia la multitarea nos permite ejecutar varios procesos a la vez; es decir, de forma concurrente y por tanto eso nos permite hacer programas que se ejecuten en menor tiempo y sean más eficientes. Evidentemente no podemos ejecutar infinitos procesos de forma concurrente ya que el hardware tiene sus limitaciones, pero raro es a día de hoy los ordenadores que no tengan más de un núcleo por tanto en un procesador con dos núcleos se podrían ejecutar dos procesos a la vez y así nuestro programa utilizaría al máximo los recursos hardware. Para que veáis la diferencia en un par de imágenes, supongamos que tenemos un programa secuencial en el que se han de ejecutar 4 procesos; uno detrás de otro, y estos tardan unos segundos:

Threads_Un_unico_hilo

Si en vez de hacerlo de forma secuencial, lo hiciésemos con 4 hilos, el programa tardaría en ejecutarse solo 20 segundos, es decir el tiempo que tardaría en ejecutarse el proceso más largo. Esto evidentemente sería lo ideal, pero la realidad es que no todo se puede paralelizar y hay que saber el número de procesos en paralelo que podemos lanzar de forma eficiente. En principio en esta entrada no vamos a hablar sobre ello ya que el objetivo de la misma es ver como se utilizan los hilos en java con un ejemplo relativamente sencillo y didáctico.

Threads_Varios_hilos

En Java para utilizar la multitarea debemos de usar la clase Thread (es decir que la clase que implementemos debe heredar de la clase Thread) y la clase Thread implementa la Interface Runnable. En el siguiente diagrama de clase mostramos la Interface Runnable y la clase Thread con sus principales métodos:

MultiHilos_Jarroba_Diagrama_de_clases

En esta entrada no vamos a ver como utilizar todos los métodos de la clase Thread, pero os los mostramos para que sepáis que existen y a parte por su nombre podéis intuir su funcionalidad.

En esta entrada vamos a poner un ejemplo para que veáis las ventajas de la multitarea, viendo como se ejecutaría un programa sin utilizar la multitarea y otro utilizándola.

En este ejemplo vamos a simular el proceso de cobro de un supermercado; es decir, unos clientes van con un carro lleno de productos y una cajera les cobra los productos, pasándolos uno a uno por el escaner de la caja registradora. En este caso la cajera debe de procesar la compra cliente a cliente, es decir que primero le cobra al cliente 1, luego al cliente 2 y así sucesivamente. Para ello vamos a definir una clase "Cajera" y una clase "Cliente" el cual tendrá un "array de enteros" que representaran los productos que ha comprado y el tiempo que la cajera tardará en pasar el producto por el escaner; es decir, que si tenemos un array con [1,3,5] significará que el cliente ha comprado 3 productos y que la cajera tardara en procesar el producto 1 '1 segundo', el producto 2 '3 segundos' y el producto 3 en '5 segundos', con lo cual tardara en cobrar al cliente toda su compra '9 segundos'.

Explicado este ejemplo vamos a ver como hemos definido estas clases:

Clase "Cajera.java":

public class Cajera {

	private String nombre;

	// Constructor, getter y setter

	public void procesarCompra(Cliente cliente, long timeStamp) {

		System.out.println("La cajera " + this.nombre + 
				" COMIENZA A PROCESAR LA COMPRA DEL CLIENTE " + cliente.getNombre() + 
				" EN EL TIEMPO: " + (System.currentTimeMillis() - timeStamp) / 1000	+
				"seg");

		for (int i = 0; i < cliente.getCarroCompra().length; i++) { 
				this.esperarXsegundos(cliente.getCarroCompra()[i]); 
				System.out.println("Procesado el producto " + (i + 1) +  
				" ->Tiempo: " + (System.currentTimeMillis() - timeStamp) / 1000 + 
				"seg");
		}

		System.out.println("La cajera " + this.nombre + " HA TERMINADO DE PROCESAR " + 
				cliente.getNombre() + " EN EL TIEMPO: " + 
				(System.currentTimeMillis() - timeStamp) / 1000 + "seg");

	}


	private void esperarXsegundos(int segundos) {
		try {
			Thread.sleep(segundos * 1000);
		} catch (InterruptedException ex) {
			Thread.currentThread().interrupt();
		}
	}

}

Clase "Cliente.java":

public class Cliente {

	private String nombre;
	private int[] carroCompra;

	// Constructor, getter y setter

}

Si ejecutásemos este programa propuesto con dos Clientes y con un solo proceso (que es lo que se suele hacer normalmente), se procesaría primero la compra del Cliente 1 y después la del Cliente 2, con lo cual se tardará el tiempo del Cliente 1 + Cliente 2. A continuación vamos a ver como programamos el método Main para lanzar el programa. CUIDADO: Aunque hayamos puesto dos objetos de la clase Cajera (cajera1 y cajera2) no significa que tengamos dos cajeras independientes, lo que estamos diciendo es que dentro del mismo hilo se ejecute primero los métodos de la cajera1 y después los métodos de la cajera2, por tanto a nivel de procesamiento es como si tuviésemos una sola cajera:

Clase "Main.java":

public class Main {

	public static void main(String[] args) {

		Cliente cliente1 = new Cliente("Cliente 1", new int[] { 2, 2, 1, 5, 2, 3 });
		Cliente cliente2 = new Cliente("Cliente 2", new int[] { 1, 3, 5, 1, 1 });

		Cajera cajera1 = new Cajera("Cajera 1");
		Cajera cajera2 = new Cajera("Cajera 2");

		// Tiempo inicial de referencia
		long initialTime = System.currentTimeMillis();

		cajera1.procesarCompra(cliente1, initialTime);
		cajera2.procesarCompra(cliente2, initialTime);
	}
}

Si ejecutamos este código tendremos lo siguiente:

La cajera Cajera 1 COMIENZA A PROCESAR LA COMPRA DEL CLIENTE Cliente 1 EN EL TIEMPO: 0seg
Procesado el producto 1 ->Tiempo: 2seg
Procesado el producto 2 ->Tiempo: 4seg
Procesado el producto 3 ->Tiempo: 5seg
Procesado el producto 4 ->Tiempo: 10seg
Procesado el producto 5 ->Tiempo: 12seg
Procesado el producto 6 ->Tiempo: 15seg
La cajera Cajera 1 HA TERMINADO DE PROCESAR Cliente 1 EN EL TIEMPO: 15seg
La cajera Cajera 2 COMIENZA A PROCESAR LA COMPRA DEL CLIENTE Cliente 2 EN EL TIEMPO: 15seg
Procesado el producto 1 ->Tiempo: 16seg
Procesado el producto 2 ->Tiempo: 19seg
Procesado el producto 3 ->Tiempo: 24seg
Procesado el producto 4 ->Tiempo: 25seg
Procesado el producto 5 ->Tiempo: 26seg
La cajera Cajera 2 HA TERMINADO DE PROCESAR Cliente 2 EN EL TIEMPO: 26seg

Como vemos se procesa primero la compra del cliente 1 y después la compra del cliente 2 tardando en procesar ambas compras un tiempo de 26 segundos.

Compra_1_cajera_1_hilo

¿Y si en vez de procesar primero un cliente y después otro, procesásemos los dos a la vez?, ¿Cuanto tardaría el programa en ejecutarse?. Pues bien si en vez de haber solo una Cajera (es decir un solo hilo), hubiese dos Cajeras (es decir dos hilos o threads) podríamos procesar los dos clientes a la vez y tardar menos tiempo en ejecutarse el programa. Para ello debemos de modificar la clase "Cajera.java" y hacer que esta clase herede de la clase Thread para heredar y sobre-escribir algunos de sus métodos. Primero vamos a ver como codificamos esta nueva clase "CajeraThread.java" y después explicamos sus caracteristicas.

public class CajeraThread extends Thread {

	private String nombre;

	private Cliente cliente;

	private long initialTime;

	// Constructor, getter & setter

	@Override
	public void run() {

		System.out.println("La cajera " + this.nombre + " COMIENZA A PROCESAR LA COMPRA DEL CLIENTE " 
					+ this.cliente.getNombre() + " EN EL TIEMPO: " 
					+ (System.currentTimeMillis() - this.initialTime) / 1000 
					+ "seg");

		for (int i = 0; i < this.cliente.getCarroCompra().length; i++) { 
			this.esperarXsegundos(cliente.getCarroCompra()[i]); 
			System.out.println("Procesado el producto " + (i + 1) 
			+ " del cliente " + this.cliente.getNombre() + "->Tiempo: " 
			+ (System.currentTimeMillis() - this.initialTime) / 1000 
			+ "seg");
		}

		System.out.println("La cajera " + this.nombre + " HA TERMINADO DE PROCESAR " 
						+ this.cliente.getNombre() + " EN EL TIEMPO: " 
						+ (System.currentTimeMillis() - this.initialTime) / 1000 
						+ "seg");
	}

	private void esperarXsegundos(int segundos) {
		try {
			Thread.sleep(segundos * 1000);
		} catch (InterruptedException ex) {
			Thread.currentThread().interrupt();
		}
	}

}

Lo primero que vemos y que ya hemos comentado es que la clase "CajeraThread" debe de heredar de la clase Thread: "extendsThread".

Otra cosa importante que vemos es que hemos sobre-escrito el método  "run()" (de ahi la etiqueta @Override) . Este método es imprescindibles sobre-escribirlo (ya que es un método que esta en la clase Runnable y la clase Thread Implementa esa Interface) porque en él se va a codificar la funcionalidad que se ha de ejecutar en un hilo; es decir, que lo que se programe en el método "run()" se va a ejecutar de forma secuencial en un hilo. En esta clase "CajeraThread" se pueden sobre-escribir más métodos para que hagan acciones sobre el hilo o thread como por ejemplo, parar el thread, ponerlo en reposos, etc. A continuación vamos a ver como programamos el método Main para que procese a los clientes de forma paralela y ver como se tarda menos en procesar todo. El método Main esta en la clase "MainThread.java" que tiene el siguiente contenido:

public class MainThread {

	public static void main(String[] args) {

		Cliente cliente1 = new Cliente("Cliente 1", new int[] { 2, 2, 1, 5, 2, 3 });
		Cliente cliente2 = new Cliente("Cliente 2", new int[] { 1, 3, 5, 1, 1 });

		// Tiempo inicial de referencia
		long initialTime = System.currentTimeMillis();
		CajeraThread cajera1 = new CajeraThread("Cajera 1", cliente1, initialTime);
		CajeraThread cajera2 = new CajeraThread("Cajera 2", cliente2, initialTime);

		cajera1.start();
		cajera2.start();
	}
} 

Ahora vamos a ver cual sería el resultado de esta ejecución y vamos a comprobar como efectivamente el programa se ejecuta de forma paralela y tarda solo 15 segundos en terminar su ejecución:

La cajera Cajera 1 COMIENZA A PROCESAR LA COMPRA DEL CLIENTE Cliente 1 EN EL TIEMPO: 0seg
La cajera Cajera 2 COMIENZA A PROCESAR LA COMPRA DEL CLIENTE Cliente 2 EN EL TIEMPO: 0seg
Procesado el producto 1 del cliente Cliente 2->Tiempo: 1seg
Procesado el producto 1 del cliente Cliente 1->Tiempo: 2seg
Procesado el producto 2 del cliente Cliente 2->Tiempo: 4seg
Procesado el producto 2 del cliente Cliente 1->Tiempo: 4seg
Procesado el producto 3 del cliente Cliente 1->Tiempo: 5seg
Procesado el producto 3 del cliente Cliente 2->Tiempo: 9seg
Procesado el producto 4 del cliente Cliente 2->Tiempo: 10seg
Procesado el producto 4 del cliente Cliente 1->Tiempo: 10seg
Procesado el producto 5 del cliente Cliente 2->Tiempo: 11seg
La cajera Cajera 2 HA TERMINADO DE PROCESAR Cliente 2 EN EL TIEMPO: 11seg
Procesado el producto 5 del cliente Cliente 1->Tiempo: 12seg
Procesado el producto 6 del cliente Cliente 1->Tiempo: 15seg
La cajera Cajera 1 HA TERMINADO DE PROCESAR Cliente 1 EN EL TIEMPO: 15seg

En este ejemplo vemos como el efecto es como si dos cajeras procesasen la compra de los clientes de forma paralela sin que el resultado de la aplicación sufra ninguna variación en su resultado final, que es el de procesar todas las compras de los clientes de forma independiente. De forma gráfica vemos que el programa ha realizado lo siguiente en dos hilos distintos:

Compra_2_hilos

Otra forma de hacer lo mismo pero sin heredar de la clase "Thread" es implementar la Interface "Runnable". En este caso no dispondremos ni podremos sobre-escribir los métodos de la clase Thread ya que no la vamos a utilizar y solo vamos a tener que sobre-escribir el método "run()". En este caso solo será necesario implementar el método "run()" para que los procesos implementados en ese método se ejecuten en un hilo diferente. Vamos a ver un ejemplo de como utilizando objetos de las clases "Cliente.java" y "Cajera.java" podemos implementar la multitarea en la misma clase donde se llama al método Main de la aplicación. A continuación vemos la codificación en la clase "MainRunnable.java":

public class MainRunnable implements Runnable{
	
	private Cliente cliente;
	private Cajera cajera;
	private long initialTime;
	
	public MainRunnable (Cliente cliente, Cajera cajera, long initialTime){
		this.cajera = cajera;
		this.cliente = cliente;
		this.initialTime = initialTime;
	}

	public static void main(String[] args) {
		
		Cliente cliente1 = new Cliente("Cliente 1", new int[] { 2, 2, 1, 5, 2, 3 });
		Cliente cliente2 = new Cliente("Cliente 2", new int[] { 1, 3, 5, 1, 1 });
		
		Cajera cajera1 = new Cajera("Cajera 1");
		Cajera cajera2 = new Cajera("Cajera 2");
		
		// Tiempo inicial de referencia
		long initialTime = System.currentTimeMillis();
		
		Runnable proceso1 = new MainRunnable(cliente1, cajera1, initialTime);
		Runnable proceso2 = new MainRunnable(cliente2, cajera2, initialTime);
		
		new Thread(proceso1).start();
		new Thread(proceso2).start();

	}

	@Override
	public void run() {
		this.cajera.procesarCompra(this.cliente, this.initialTime);
	}

}

En este caso implementamos el método "run()" dentro de la misma clase donde se encuentra el método Main, y en el llamamos al método de "procesarCompra()" de la clase Cajera. Dentro del método Main, nos creamos dos objetos de la misma clase en la que estamos ("new MainRunnable") y nos creamos dos objetos de la clase Thread para lanzar los proceso y que se ejecuten estos en paralelo. El resultado de esta ejecución es el mismo que en el caso anterior:

La cajera Cajera 2 COMIENZA A PROCESAR LA COMPRA DEL CLIENTE Cliente 2 EN EL TIEMPO: 0seg
La cajera Cajera 1 COMIENZA A PROCESAR LA COMPRA DEL CLIENTE Cliente 1 EN EL TIEMPO: 0seg
Procesado el producto 1 del cliente Cliente 2->Tiempo: 1seg
Procesado el producto 1 del cliente Cliente 1->Tiempo: 2seg
Procesado el producto 2 del cliente Cliente 2->Tiempo: 4seg
Procesado el producto 2 del cliente Cliente 1->Tiempo: 4seg
Procesado el producto 3 del cliente Cliente 1->Tiempo: 5seg
Procesado el producto 3 del cliente Cliente 2->Tiempo: 9seg
Procesado el producto 4 del cliente Cliente 2->Tiempo: 10seg
Procesado el producto 4 del cliente Cliente 1->Tiempo: 10seg
Procesado el producto 5 del cliente Cliente 2->Tiempo: 11seg
La cajera Cajera 2 HA TERMINADO DE PROCESAR Cliente 2 EN EL TIEMPO: 11seg
Procesado el producto 5 del cliente Cliente 1->Tiempo: 12seg
Procesado el producto 6 del cliente Cliente 1->Tiempo: 15seg
La cajera Cajera 1 HA TERMINADO DE PROCESAR Cliente 1 EN EL TIEMPO: 15seg

CONCLUSIONES Y ACLARACIONES:

El concepto de multitarea o multiprocesamiento es bastante sencillo de entender ya que solo consiste en hacer varias cosas a la vez sin que se vea alterado el resultado final. Como ya se ha dicho en la entrada no todo se puede paralelizar y en muchas ocasiones suele ser complicado encontrar la manera de paralelizar procesos dentro de una aplicación sin que esta afecte al resultado de la misma, por tanto aunque el concepto sea fácil de entender el aplicarlo a un caso práctico puede ser complicado para que el resultado de la aplicación no se vea afectado.

Por otro lado para los que empecéis a ver estos temas de la concurrencia, multitarea y demás, no so preocupéis al principio si os cuesta programar problemas de este tipo ya que a parte de la multitarea se mezclan cosas como la herencia y las Interfaces que al principio son cosas que cuestan de asimilar, así que ir poco a poco pero tener muy claro que la multitarea es muy util y se ha de aplicar para hacer las aplicaciones más eficientes y que den mejor rendimiento.

Comparte esta entrada en:
Safe Creative #1401310112503
Multitarea e Hilos en Java con ejemplos (Thread & Runnable) por "www.jarroba.com" esta bajo una licencia Creative Commons
Reconocimiento-NoComercial-CompartirIgual 3.0 Unported License.
Creado a partir de la obra en www.jarroba.com

94 thoughts on “Multitarea e Hilos en Java con ejemplos (Thread & Runnable)”

  1. Hola, estoy trabajando con hilos en Android y estoy buscando una forma de detener el hilo a mitad de la ejecución, si tienes alguna entrada o una idea de como se puede hacer te lo agradecería infinitamente

  2. La mejor manera que he encontrado de explicar los hilos.
    Una consulta…. que diferencia hay entre definir las variables antes del @Override y despues de éste?
    Saludos

  3. Muy bien explicado el tema de los hilos. Soy novato en todo lo referente a Java.
    Pregunta: necesito me guíes sobre si esto de los hilos me sirve para lanzar un listado consultando una base de datos (hilo1) y a la vez indicarle al usuario a través de un mensaje en pantalla o un reloj de arena, que espere (hilo2) mientras se lleva a cabo el proceso de selección de registros para su visualización. Sinó, por donde debo atacar el tema,
    Gracias.

    1. Esa es la idea de la paralelización de tareas, mientras con un hilo pintas la interfaz gráfica al usuario, con otro hilo lanzas las consultas a una base de datos. De esta manera el usuario no queda bloqueado y puede ver que la consulta está trabajando o incluso puede usar otras partes de la aplicación.

      1. Hola disculpa quiero emplear algo similar a esto pero la temática es la siguiente

        Desarrollar un programa en Java que implemente hilos implementando el interface Runnable. El programa debe crear 2 hilos, cada hilo realizará lo siguiente:

        -Debe existir un hilo que calcule y muestre la serie fibonacci (de números enteros positivos, iniciando en 1).
        -Debe existir un hilo que calcule y muestre la serie factorial (de números enteros positivos, iniciando en 1).

        Funcionalidad:
        – Crear los objetos hilos y asignar nombre a los hilos según procedimiento solicitado («fibonocci»,»factorial»).
        – Asignar prioridad a los hilos: fibonacci (máxima prioridad) y factorial (mínima prioridad).
        – Dormir a cada uno de los hilos 1 segundo por cada numero mostrado en pantalla.
        – Mostrar en consola de NetBeans la serie de números según hilo en ejecución junto con el nombre del hilo y su prioridad.
        Ejemplo: Recordar que la ejecución de los hilos es asíncrona.
        Factorial: 1 con prioridad de 1
        Factorial: 2 con prioridad de 1
        Fibonnacci: 1 con prioridad de 10
        Factorial: 6 con prioridad de 1
        Fibonacci: 1 con prioridad de 10
        Fibonacci: 2 con prioridad de 10

        – Crear una ventana (JFrame) la cual deberá contener 2 botones, uno llamado «Iniciar» y otro «Salir»; el botón calcular lanzara los hilos y mostrará en consola de NetBeans los resultados antes descritos, el botón salir permitirá al usuario terminar el programa, los cálculos de la sucesión los números (factorial y fibonacci) serán realizados y mostrados en pantalla de manera indefinida hasta que el programa sea finalizado.

        Me podrias apoyar con una orientacion por favor si no es mucho pedir

        1. Tienes toda la información en este artículo, te doy unas pistas: los dos hilos que te piden calcular fibonacci y factorial son para este artículo las Cajeras (concretamente el método procesarCompra).

          Por otro lado, recuerdo que no hacemos ejercicios por ética, más información sobre esto en https://jarroba.com/faq/

      2. Hola Ramón, se ve que tienes muchos conocimientos… Quisiera saber, hoy en dia para el desarrollo web con java en el backend, se suele usar los threads o los sockets en su desarrollo???

        1. Hola Lester.

          Pues depende de las necesidades. Sugiero echar un vistazo a algún framework como Spring para la parte de backend que facilitará mucho el desarrollo tanto de sockets como de hilos. Por otro lado, no quita el tener que aprender la base de hilos y sockets, por lo que al menos hay que entenderlo.

  4. Holaa, crees que este código puede aplicarse a este ejercicio?

    Carrera de carros:

    Habrá una carrera con 5 carros, cada carro correrá en un hilo diferente.
    Además cada carro deberá ir generando un número aleatorio entre 1 y 6 para definir el paso que irá dando.
    Se alcanzará la meta cuando el carro llegue a 1000 puntos o más. Apenas el carro alcanza los puntos debe imprimir
    su nombre y el tiempo en segundos que tardó en hacer el recorrido.

    Ayuda, gracias!!

    1. Hola Erika.
      Sí se podría aplicar adaptándolo. Necesitarás 5 hilos para ir tratando cada uno de los carros.

  5. Alguien me podría ayudar con este código tengo una duda aquí…

    Diseñar un hilo que permita ingresar los nombres de los usuarios que inician sesión e indicar el tiempo de sesión activa

    import java.util.*;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    public class nombresdeusuarioytiempodesesión extends Thread{
    Scanner dato = new Scanner(System.in);
    String n;
    double h;
    public nombresdeusuarioytiempodesesión(String nombre, String dia, double hora){
    n=nombre;
    h=hora;
    System.out.println(«Hola usuario bienvenido»);
    System.out.println(«Ingrese los nombres de los usuarios : «);
    n = dato.next();
    System.out.println(«Ingrese el tiempo de sesión activa : «);
    h = dato.nextDouble();

    }
    public void run(){
    if(h>24.0){
    System.out.println(n + » nombre de los usuarios » + n);
    }else{
    System.out.println(n + » tiene un tiempo de sesión activa de » + h);
    }
    }
    public static void main(String []args) throws InterruptedException{

    try {
    Thread.sleep(3000);
    } catch (InterruptedException ex) {
    Logger.getLogger(nombresdeusuarioytiempodesesión.class.getName()).log(Level.SEVERE, null, ex);
    }
    Thread usuario1 = new nombresdeusuarioytiempodesesión(» «,» «,0);
    usuario1.start();
    Thread usuario2 = new nombresdeusuarioytiempodesesión(» «,» «,0);
    usuario2.start();
    }
    }

  6. Amigo que Aplicacion utilizas tengo 14 años y me interesa el mundo de la programacion uso netbeans y eclipse y me marca error me podrias ayudar porfavor y disculpa mi ignorancia en el tema

    1. Hola Arturh.
      Si me puedes pegar el error te podré ayudar mejor. Pero creo que podría ser por no estar instalado Java o están sin configurar las variables de entorno del sistema, tienes paso a paso en este artículo como se hace: https://jarroba.com/instalar-bien-eclipse-un-ide-de-muchos/ y tienes un tutorial de Java desde cero en https://jarroba.com/mucho-java-en-un-sencillo-tutorial-aqui-los-dummies-se-hacen-de-oro/
      ¡Y ánimo con la programación! Te puedo asegurar que es un camino apasionante 😉

      1. buenas tardes quiero aplicar esto a un codigo de procesamiento de imagenes OCR estracion de texto, podrias ayudarme con esto ya tengo mi projecto de OCr pero demora mucho si son varias imagenes

        1. Buenas Diego.
          Podrías enviar a cada procesador de OCR una imagen (desde un hilo principal) para que paralelamente se procesen cada una en un hilo.

  7. Buenas Tardes.
    Tengo Una duda realizando el ejercicio en mi pc siempre me genera error en la clase cajera dentro del for en la primera y segunda linea me gustaría saber como hago para quitarlos no se si deba llamar a length para que no suceda esta
    Gracias

    1. El length es necesario para que el for conozca la cantidad de veces que ha de recorrer, pues en cada iteración se incrementa +1 hasta alcanzar esa cantidad ¿Qué error te sale exactamente?

      1. amigo estoy aprendiendo a programar e intento correr tu codigo y me da errores podras pasarmelo ?

          1. Puede ser porque hayas movido el proyecto de directorio.
            Primero haz una copia de seguridad de tu proyecto a otra ubicación.
            En Eclipse lo más fácil que puedes probar es en «Project» pulsar «Clean» para limpiar la caché y esperar a que Eclipse termine de reprocesar el proyecto.
            Si no se soluciona tendrás que ir a «Project» luego a «Properties», «JavaBuildPath» y en «Libraries» eliminar o solucionar (posiblemente la ruta sea errónea) lo que te de error y volverlo a cargar si lo necesitas.

  8. Hola, gracias por la explicación, muy completa por cierto.
    Por mi cuenta, estoy realizando un «chat» (comunicación entre cliente y servidor) tengo un hilo principal que me conecta ambas interfaces, puedo recibir los primeros mensajes al realizar la coneccion («Se ha conectado un cliente» && «Usted se conectó con exito»), pero al tratar de agregar un nuevo mensaje el programa me lanza una excepción (Este es mi problema) pues no he encontrado la forma de agregar mis nuevos mensajes al hilo que ya estoy manejando.
    De verdad te agradecería si me dieras un pequeño empujón con un ejemplo o una idea clara. De antemano muchas gracias por el tiempo y nuevamente gracias por el tutorial.

  9. hola, muy claro y facil de entender. Ahora bien, todos los ejemplos que veo de hilos, son usando la misma clase del hilo. Yo estoy haciendo un simulador de ascensores, con interfaz grafica. y necesito usar dos hilos de diferentes clases. no encuentro tutorial sobre eso. necesito usar un hilo qe maneje los ascensores y otro que vaya actualizando la interfaz grafica para que se vea el «movimiento» del ascensor. muchas gracias

  10. Magnifico tutorial y muy bien explicado. Espero nuevos tutoriales sobre sincronizacion, semaforos y sincronizacion hilos.
    Una cosa que igual es conceptual y diria con todos los respetos que igual no esta bien conseguida. No necesitarias mas que una cajera que podria ser generica para ejecutar de forma concurrente los procesos. Es en realidad el proceso1 y proceso2 lo que realmente hacen que «haya dos cajeras» y los productos se puedan procesar en paralelo. Cada hilo llama a cajera.procesar compra y ya esta…. Si hacemos lo siguiente ( utilizando una sola cajera funcionaria igual):

    Runnable proceso1 = new CajeraRunnable(«cajera1», cliente1, initialTime);
    Runnable proceso2 = new CajeraRunnable(«cajera1», cliente2, initialTime);

    new Thread(proceso1).start();
    new Thread(proceso2).start();

    Despues ya complicarias el tema, pero podria darse el caso que el proceso 1 tuviera una cajera procesando un array de clientes y el proceso2 otra cajera tambien procesando un array de clientes. Pero de nuevo no creo que eso de la concurrencia, sino la posibilidad de tener una cajera que procese los datos.

  11. Buenas excelente articulo. Haria un par de observaciones: lo he leido en comentarios pero podrias incluirlo en el articulo, porque heredar de Runnable y de Threads, que ventajas inconvenientes queda. Otro apunte es que al final no mencionas el tema de los join para esperar y hacer una finalizacion limpia habiendo gestionado todos los clientes. El tercer apunte es que he visto muchos tutoriales, en que tienes un MainRunnable similar al tuyo donde se declaran los threads y se lanzan y un WorkerClass Runnable donde estaria cliente,cajera y se gestionaria en el run() el procesoCompra ( todo el trabajo que quieres realizar). Creo que seria un codigo mas limpio y por analogia valido para otros casos similares.
    Igual daria para otro artículo la utilización de Runnable y Callable y retorno de tipos, asi como otros metodos para lanzar hilos como execute o submit, y metodos para finalizar tipo invokeany, invokeall etc…

    Gracias de nuevo por tu trabajo. Espero nuevos tutoriales sobre lo comentado o semaforos, sincronizacion, fork/join etc…..

  12. Muy bueno el ejercicio!! muchas gracias, es de gran utilidad. ¿Sabrias como hay que hacer para poder testear esto con JUnit?

    1. Un poco amplia la pregunta. Depende de lo que quieras testear puedes hacer unos assert u otros. Por ejemplo jugando con Thread.sleep() puedes simular unas ejecuciones con esperas u otras. Bien es cierto que podría darte resultados diferentes en cada ejecución, podrías esperar al join() final para que te de resultados esperables o dentro de un margen.

  13. Una duda, quiero utulizar 2 hilos, un hilo tiempo y un hilo de escritura infinito, lo que quiero hacer es que cuando el hilo tiempo finalice, que el hilo de escritura también finalice. ¿Qué me recomiendas utilizar en ese caso?

  14. Hola Buenos días, me estoy iniciando recién con los temas de hilos y me a surgido una duda. Al ocupar el metodo join() para que finalice un hilo antes de comenzar el otro hilo, con este metodo, el funcionamiento de hilos ya no aplicaria.?? ya que la idea no es que se ejecuten paralelo.?? Muchas gracias.

    1. Cuando llamas a strart() se inicia un segundo hilo, pero le hilo principal continua. El hilo principal continua hasta que llega al join(), donde espera a que termine el hilo segundo. Por lo que sí aplica el funcionamiento de hilos (al menos siempre está el hilo principal, más lo que inicies con start() ) aunque luego venga otro hilo 😉

  15. disculpa si mi clase cajera yo la voy a manejar con Cola y tengo 3 cajeras y quiero q la tres cajeras realicen su proceso al mismo tiempo bueno cada vez que tengan un cliente. se puede realizar con hilos??

    1. Entiendo que vas a utilizar la clase Queue (o la estructura de datos que necesites: List, Array, etc) y que vas a tener ahí los tres Threads. Si vas desapilando cada uno e iniciándo (start) cada hilo, te debería de funcionar como necesitas.

  16. Tengo una duda.. si quiero correr varios hilos para realizar una tarea, un for por ejemplo, pero la siguiente tarea debe esperar que todos esos hilos terminen, como se realiza?

    1. Puedes utilizar el método join() para esperar a que terminen los hilos y continuar desde ese punto:

      Thread t1 = new Thread();

      Thread t2 = new Thread();

      Thread t3 = new Thread();

      Thread t4 = new Thread();

      t1.start();

      t2.start();

      t3.start();

      t4.start();

      // Para esperar en este hilo a que acaben los anteriores hilos iniciados, utilizamos join()

      t1.join();

      t2.join();

      t3.join();

      t4.join();

  17. Buen tutorial, pero mi duda es que dejaste el @override en run cuando implementas Runnable y el eclipse marcca erróneo.

    saludos

    1. La anotación @override marca sobrescritura, es más para facilitar la lectura del programador, para que se sepa que se está sobrescribiendo. No es obligatorio, por lo que si la configuración de Eclipse te da error puedes quitarlo. De cualqueir manera, es un poco extraño que te de error las anotaciones, puede que estés trabajando con una versión antigua de Java.

  18. Hola instructores. Tengo un  ejemplo de JLabel con una pelota que rebota en los bordes con diferentes ángulos. y mi labor es hacer que por cada CLICK que yo haga dentro del JLabel me aparezca una nueva pelota.

    Como hago eso, yo soy nuevo en esto y es mi primer laboratorio de este semeste.

    Aqui les copio lo que me estan pidiendo.

    Modify the program so that the Sprite class implements the Runnable interface and the sprite moves itself (25 times per second, which is the original frame rate) with its own thread of execution (the invocation of the sprite's move method will no longer belong in the main animation loop of the SpritePanel). 3. Modify the program so that each additional mouse click adds an additional bouncing sprite rather than replacing the previous sprite. 4. Run the jvisualvm program included with the JDK to confirm that each sprite on the screen has its own thread of execution. (Your Professor has demonstrated how to use this program in the Lecture and/or Lab class.)

    1. No te puedo dar la solucción completa, pues sería contraproducente para tus estudios e iría en contra de nuestros principios de enseñar (y de la misión de tu profesor para que aprendas); pero te puedo dar unas pistas: Si la pelota se mueve sin tener que bloquearse y el usuario tiene que hacer click sin tener que bloquearse, puede que lo más apropiado sean unos hilos. El resto ya es practicar 😉

      1. buenos dias tengo un pequeño problema con mi aplicacion en java, cuando ingreso a un formulario se tarda al menos 6 segundos en mostrar el formulario, pero creo que es por que estoy realizando consultas a la base de datos y cuando las dejo comentariadas me abre al instante no se como me pueden ayudar a solucionar ese tema sin con tarea asincronas o hilos no se estoy confundido en esa parte

  19. Hola. Excelente Tutorial. Hago Una consulta. Estoy tratando de dibujar en un JLabel varias pelotitas que rebotan en los bordes con diferentes ángulos. Trato que cada pelota sea un hilo (thread) y que tenga conciencia de los limites y angulos para rebotar. Tengo un problema que con dibujar y redibujar su posicion contantemente, como deberia manejar el repaint? tengo entendido que tambien es un hilo el que pinta y repinta? los componentes.

  20. Te hago una consulta, una vez que sabes cual es el hilo que esta corriendo (runnable) hay forma de saber que clase es la que se esta ejecutando y a su vez que metodo de esa clase?

  21. Tengo una pregunta, cómo se implementaría si en vez de ser dos clientes fueran n clientes? es decir, hay dos cajeras pero para un número indeterminado de clientes y si quieres rizar más el rizo, que se sitúan de forma aleatoria en una cajera u otra…

    Muchas gracias.

  22. Muy buen tutorial sobre el tema. solo me queda una duda que no he conseguido ver como hacer y es como mediante Runnnable arancar dos procesos diferentes, en vez de dos copias del mismo (cajera). si lo he conseguido mediante threads y con esto me ha valido. La pregunta es unicamente por curiosidad y formacion.

     

     

  23. Richard, tengo una duda, a ver si me puedes ayudar. Tengo que lanzar unos modelos de simulación numérica cuyo proceso lleva bastante tiempo. El programa tiene implementada la opción de paralelización, y tengo en el PC un dispositivo que permite proceso GPU. Tengo que optimizar el tiempo al máximo, así que quiero ejecutar varios procesos a la vez. En el PC tengo 4 cores, así que entiendo que no debo definir más de 4 threads, pero mi duda es la siguiente: ¿cómo puede ser más eficaz la ejecución de los procesos simultáneos? No tengo claro cómo funciona lo del GPU y la paralelización, porque hasta ahora manejaba otro PC, en el que una vez lanzado el proceso accedía al administrador de tareas y modificaba ahí la afinidad de cada no en función de los núcleos. Mi duda es si debo ejecutar 4 procesos de forma simultánea activando en todos ellos el GPU y estableciendo un único thread en cada uno, o si es mas eficaz ejecutarlos estableciendo más de un thread. Si ejecuto los 4 procesos de cálculo a la vez y defino 4 threads en cada uno, ¿estoy mejorando la eficacia o de esa forma no paralelizo nada? ¿Para mejorar la eficacia es necesario que establezca un solo thread para cada proceso?

    He hecho una prueba y si ejecuto dos simulaciones a la vez estableciendo 4 threads en cada una de ellas, tarda justo la mitad que si ejecuto 4 simulaciones a la vez con 4 threads en cada una (en todos los casos activando el GPU), por lo que me parece que no estoy paralelizando nada…

    Gracias

  24. Gracias por el aporte, he tomado de lo que has publicado para mi proyecto, ufff fue díficil porque es una mezcla entre clase que implementa Runnable y un actualidador de lista de canales RSS.

  25. Que buen artículo, se agradece siempre el compartir los conocimientos 🙂

    Tengo una duda que quisiera ver si me puedes explicar, soy novato en Java…

    Si tuviera un archivo de tipo txt que quisiera leer X cantidad de veces de forma paralela (por ejemplo 5 hilos, leer de forma paralela 5 veces el archivo)… ¿Cómo tendría que ser la rutina para esto?…

    Gracias de antemano!

    1. No he probado a abrir varias veces el mismo fichero con varios hilos, pero seguramente cuando lo abras con un hilo lo bloquearás y no te permitirá abrirlo con más. Simplemente obtén el contenido del fichero en una variable y multiplícalo en cada hilo que quieras realizar la lectura.

  26. hola,

    si quisiera que  un proceso  corra durante unos minutos, (suponiendo que se generan ls clientes  aleatoriamente) como hago para dejarlo corriendo en un ciclo mientras con la condicion de que no hallan pasado los dos minutos?? se puede hacer eso???

    1. Hola Irene. Puedes hacer lo fácil (aunque a mí no me gusta mucho y no te asegura que justo a los 2 minutos se termine) que es «System.currentTimeMillis()» para capturar el tiempo actual en milisegundos, y sumarle dos minutos para obtener el momento de parada, solo te quedaría ir preguntando a cada iteración si se ha sobrepasado el tiempo. Otra es utilizar las clases Timer de Java, tienes ejemplos en https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html

  27. muy buen articulo, tienen alguna informacion de git y github no me ha quedado del todo claro su manejo
    gracias

  28. Hola, 

    El proyecto de este post no esta disponible, podrian ponerlo.

    Muy bueno este y demas post de POO.

    Gracias

     

    1. Hola Adolfo.

      Ya tienes el proyecto compartido en Git, que por algún motivo debimos borrar el repositorio sin querrer. Gracias por avisarnos.

      SL2

    1. Hola Jorge.

      Simplemente te debes de ir a la carpeta donde tengas es fichero java (NombreFichero.java) y poner lo siguiente: "java NombreFichero.java" y ya se ejecutará tu programa, eso siempre y cuando tengas instalada la maquina virtual java.

      SL2

  29. Hola,
    El link para descargar el proyecto al principio de esta pagina no funciona, podrían arreglarlo. Muchas gracias por todo el contenido de la pagina.

  30. !Hola! Esta muy completo lo que han explicado sobre los hilos, sin embargo tengo una duda se puede implementar creando una interfaz y como que herramientas puedo utilizar de ser así?

  31. Muy buena la explicacion de hilos. Aunque tengo una duda. Utilizando Thread si el numero de personas es mayor que el número de cajeras como lo resolvemos?

    Gracias!!

    1. Hola Jose Antonio.
      Muy buena pregunta la que planteas. Para hacer eso requiere un poco mas de control sobre los threads y aunque no es muy complejo, requiere una explicación bastante detallada como para explicarlo en un comentario. En breve publicaremos un tutorial de como hacer eso que planteas ya que estamos viendo que las entradas que hacemos sobre multiproceso están teniendo bastante exito. Gracias por tu comentario y por motivarnos ha hacer un tutorial más sobre el tema que planteas. En breve te daremos la solución en una nueva entrada.
      SL2

  32. Los felicito, ejemplo completo y entendible con código acorde a la POO, tomare este y algunos otros artículos como referencias para las clases que dicto.

  33. Saludos! Esta muy bien explicado el tema, sigan asi, muchas gracias. Me podrias decir que IDE utilizaste? esque me gustó porque esta muy legible el código, gracias!

  34. Hola gracias por la informacion, sin embargo lo que estoy buscando es el consumo de un web service por medio de multithread, me explico tengo un web service con cuatro operaciones basicas suma, resta, multiplicacion y division. la idea es que apartir de una aplicacion de escritorio se consuma el web service haciendo uso de los hilos podrias ayudarme con ello?

    yo lo he intentado de varias maneras pero siempre me ocurre que cuando llamo el metodo .start me sale un error que dice que es indefinido

    este es el codigo de invocacion

    package WebServiceMatematicas.hilos;
    import WebServiceMatematicas.ImplOpMatematicas;
    import WebServiceMatematicas.ImplOpMatematicasProxy;
    public class Proceso {
    public static void main(String[] args) {
    ImplOpMatematicas hilo1 = new ImplOpMatematicasProxy(«http://localhost:8080/WebServicedistri/services/ImplOpMatematicas»);
    hilo1.start(); //Es aca donde me aparece el error
    }
    }

    de antemano muchas gracias

  35. Gran artículo!! Es un placer leer estos temas sobre java porque ayudáis a muchas personas. Tenéis mucho mérito con todo lo que hacéis. Esta web es buenísima. Enhorabuena!

    1. Una pregunta, ¿Que diferencia hay entre crear hilos a través de la herencia de la clase Thread y crearlos a través de la implementación de la interfaz Runnable? ¿Alguna forma es la más usada por los programadores? ¿Existe alguna ventaja?

  36. Saludos.

    Soy nuevo en el área de la programación java. Y queria saber acerca de un ejemplo sencillo de como puedo manejar esto en programacion objeto. Por ejemplo como un semaforo.

  37. Hola, me parece interesante tu tutorial y la forma como explicas sobre multitarea, pero tengo una consulta, lo que haz mostrado es referente a la misma función cajera, osea hacer dos tareas simultáneas usando la misma función cajera, pero como se haría si fueran dos funciones distintas?
    Por ejemplo quiero enviar y recibir datos por socket, mi cliente en android y mi servidor en java, por el lado de mi servidor quiero que haga una multitarea, por un lado recibiendo el dato del cliente y por el otro lado en todo momento leer si ingreso un dato por teclado y enviarlo al cliente. El problema es que no se como hacer que me lea el teclado en todo momento. Tengo en un while(true) la ejecución de recepción de datos del cliente, pero imagino que tendría que usar multitarea para que me lea en todo momento el teclado y enviarlo al cliente.
    Agradecería tus comentarios!!!
    Nícolas

    1. Hola Nícolas,

      se haría de manera similar pero con dos clases diferentes. Aquí la complicación radicaría en la comunicación entre las clases que extienden de Thread, para no saltarte la seguridad de hilos (por ejemplo, evitando el interbloqueo).
      De cualquier manera, para Android no necesitas preocuparte por los hilos, ya que los eventos te solucionan esta parte. Para leer los cambios (introducción por teclado) de un EditText puedes utilizar:
      EditText et = (EditText) findViewById(R.id.miViewEditText);

      et.addTextChangedListener(new TextWatcher() {
      public void afterTextChanged(Editable s) {
      // Hacer algo después de cambiar el texto
      }

      public void beforeTextChanged(CharSequence s, int start, int count, int after) {
      // Hacer algo antes de cambiar el texto
      }

      public void onTextChanged(CharSequence s, int start, int before, int count) {
      // Hacer algo al momento de cambiar el texto
      }
      });
      }

  38. Hola amigos, excelente tutorial la verdad.
    Podrian hacer un tutorial acerca de la sincronizacion de Hilos?
    He estado buscando un poco, pero no encuentro nada asi de bien explicado como lo hacen ustedes.
    Muchas gracias!

    1. Hola Andrés,

      tenemos muchos proyectos entre los que se encuentran más tutoriales sobre hilos. Apuntamos tu sugerencia y la daremos prioridad; avisar que no lo publicaremos pronto, nos gusta hacer los artículos lo más perfectos y fáciles de comprender posible eso requiere tiempo 😉

      1. Genial, a mi me gusta mucho Java y siempre ando aprendiendo algo nuevo.
        Como les dije antes su pagina es muy ilustrativa y ayuda mucho a entender de mejor forma este lenguaje.
        Gracias!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies

ACEPTAR
Aviso de cookies