Foros del Web » Programación para mayores de 30 ;) » Java »

[SOLUCIONADO] Duda Ejecución Hilos

Estas en el tema de Duda Ejecución Hilos en el foro de Java en Foros del Web. Buenas, me estoy preparando la certificación SCJP de java y viendo un ejemplo de hilos me ha surgido una duda. Teniendo el siguiente código: @import ...
  #1 (permalink)  
Antiguo 02/04/2014, 03:43
Avatar de rgf1987  
Fecha de Ingreso: diciembre-2012
Ubicación: Asturias
Mensajes: 269
Antigüedad: 11 años, 3 meses
Puntos: 22
Duda Ejecución Hilos

Buenas, me estoy preparando la certificación SCJP de java y viendo un ejemplo de hilos me ha surgido una duda.

Teniendo el siguiente código:

Código Java:
Ver original
  1. class Reader extends Thread {
  2.     Calculator c;
  3.  
  4.     public Reader(Calculator calc) {
  5.         c = calc;
  6.     }
  7.  
  8.     public void run() {
  9.         synchronized (c) {
  10.             try {
  11.                 System.out.println("Waiting for calculation...");
  12.                 c.wait();
  13.             } catch (InterruptedException e) {
  14.             }
  15.             System.out.println("Total is: " + c.total);
  16.         }
  17.     }
  18.  
  19.     public static void main(String[] args) {
  20.         Calculator calculator = new Calculator();
  21.         new Reader(calculator).start();
  22.         new Reader(calculator).start();
  23.         new Reader(calculator).start();
  24.         calculator.start();
  25.     }
  26. }
  27.  
  28. class Calculator extends Thread {
  29.     int total;
  30.  
  31.     public void run() {
  32.         synchronized (this) {
  33.             for (int i = 0; i < 100; i++) {
  34.                 total += i;
  35.             }
  36.             notifyAll();
  37.         }
  38.     }
  39. }

Pensaba en un principio que la salida era:
Waiting for calculation...
Waiting for calculation...
Waiting for calculation...
Total is: 4950
Total is: 4950
Total is: 4950


Porque se crean los 3 hilos de la clase Reader y se ponen en espera, y luego se crea el hilo de la clase Calculator y se hace el notifyall() que los libera...
Pero para mi sorpresa, no siempre se da ese resultado, ya que por lo visto los hilos se ejecutan en un orden aleatorio en función de lo que decida la JVM.

Existe alguna forma, de controlar el orden en la que se ejecutan los hilos en la JVM? Si por ejemplo quiero que se ejecute el hilo

calculator.start();

en último lugar siempre, que debería añadir al código?
He estado haciendo pruebas, pense en ponerle un booleano y comprobar desde el run() de calculator que todos los hilos Reader estuviesen ejecutandose, pero esto no me sirve si la JVM ejecuta en un orden aleatorio.

El método yield(), se utiliza para asignar prioridades pero en este caso como debería utilirse??
  #2 (permalink)  
Antiguo 02/04/2014, 04:50
Avatar de rgf1987  
Fecha de Ingreso: diciembre-2012
Ubicación: Asturias
Mensajes: 269
Antigüedad: 11 años, 3 meses
Puntos: 22
Respuesta: Duda Ejecución Hilos

me auto respondo, lo hice de esta forma y funciona correctamente... aunque me parece demasiado lío, debería haber una forma más fácil de hacerlo:

Código Java:
Ver original
  1. import java.util.ArrayList;
  2. import java.util.List;
  3.  
  4. class Reader extends Thread {
  5.     Calculator c;
  6.     boolean ejecutado=false;
  7.  
  8.     public Reader(Calculator calc) {
  9.         c = calc;
  10.     }
  11.  
  12.     public void run() {
  13.         synchronized (c) {
  14.             try {
  15.                 System.out.println("Waiting for calculation...");
  16.                 ejecutado=true;
  17.                 c.wait();
  18.             } catch (InterruptedException e) {
  19.             }
  20.             System.out.println("Total is: " + c.total);
  21.         }
  22.     }
  23.  
  24.     public static void main(String[] args) {
  25.         Calculator calculator = new Calculator();
  26.         List<Reader> list = new ArrayList<Reader>();
  27.         Reader reader1 = new Reader(calculator);
  28.         Reader reader2 = new Reader(calculator);
  29.         Reader reader3 = new Reader(calculator);
  30.         reader1.start();
  31.         reader2.start();
  32.         reader3.start();
  33.         list.add(reader1);
  34.         list.add(reader2);
  35.         list.add(reader3);
  36.         calculator.listReader = list;
  37.         calculator.start();
  38.     }
  39. }
  40.  
  41. class Calculator extends Thread {
  42.     int total;
  43.     List<Reader> listReader;
  44.     boolean todosEjecutados = false;
  45.     public void run() {
  46.         while(!todosEjecutados){
  47.             for(Reader r:listReader){
  48.                 if(r.ejecutado){
  49.                     todosEjecutados=true;
  50.                 }
  51.                 else{
  52.                     todosEjecutados=false;
  53.                     break;
  54.                 }
  55.             }
  56.             if(todosEjecutados!=false){
  57.                 synchronized (this) {
  58.                     for (int i = 0; i < 100; i++) {
  59.                         total += i;
  60.                     }
  61.                     notifyAll();
  62.                 }
  63.             }
  64.         }  
  65.     }
  66. }

He creado una lista con los hilos Reader, y mediante un booleano indico si el hilo ha sido ejecutado o no:

Código Java:
Ver original
  1. synchronized (c) {
  2.             try {
  3.                 System.out.println("Waiting for calculation...");
  4.                 ejecutado=true;
  5.                 c.wait();
  6.             } catch (InterruptedException e) {
  7.             }
  8.             System.out.println("Total is: " + c.total);
  9.         }

Luego cuando se llama al hilo de Calculator, recorro la lista de objetos Reader y se ejecuta un bucle infinito hasta que todos los hilos de la lista se han ejecutado.

Código Java:
Ver original
  1. while(!todosEjecutados){
  2.             for(Reader r:listReader){
  3.                 if(r.ejecutado){
  4.                     todosEjecutados=true;
  5.                 }
  6.                 else{
  7.                     todosEjecutados=false;
  8.                     break;
  9.                 }
  10.             }
  11.             if(todosEjecutados!=false){
  12.                 synchronized (this) {
  13.                     for (int i = 0; i < 100; i++) {
  14.                         total += i;
  15.                     }
  16.                     notifyAll();
  17.                 }
  18.             }
  19.         }

Me estoy liando demasiado???
  #3 (permalink)  
Antiguo 02/04/2014, 07:07
Avatar de nup_  
Fecha de Ingreso: noviembre-2010
Mensajes: 265
Antigüedad: 13 años, 5 meses
Puntos: 32
Respuesta: Duda Ejecución Hilos

Hola:
El problema con el primer código está en que dentro del run() de Reader
Código Java:
Ver original
  1. c.wait();
asume q el thread de Calculator no ha terminado. Lo cual, como bien dices, es un error. Si el thread de Calculator ya terminó el wait va a esperar eternamente.

El resultado q quieres obtener lo puedes hacer usando Futures, Callables y Executors.
Si te interesan los temas de concurrencia en java debes estudiar acerca del API de concurrencia "java.util.concurrent" (docs). Muchos de los problemas de concurrencia q te vas a encontrar ya tienen soluciones (e incluso patrones) implementadas.

Aquí te dejo un pequeño tutorial:
http://www.vogella.com/tutorials/Jav...y/article.html
en el cap 8 resuelven un problema muy parecido al tuyo, basándose en ese código podemos llegar a este:
Código Java:
Ver original
  1. import java.util.ArrayList;
  2. import java.util.List;
  3. import java.util.concurrent.Callable;
  4. import java.util.concurrent.ExecutionException;
  5. import java.util.concurrent.ExecutorService;
  6. import java.util.concurrent.Executors;
  7. import java.util.concurrent.Future;
  8.  
  9. public class CallableFutures {
  10.     // Cantidad de hilos
  11.     private static final int NTHREDS = 3;
  12.  
  13.     public static void main(String[] args) {
  14.  
  15.         ExecutorService executor = Executors.newFixedThreadPool(NTHREDS);
  16.         List<Future<Long>> list = new ArrayList<Future<Long>>();
  17.        
  18.         Callable<Long> worker = new MyCallable();
  19.  
  20.         for (int i = 0; i < NTHREDS; i++) {
  21.             Future<Long> submit = executor.submit(worker);
  22.             list.add(submit);
  23.         }
  24.  
  25.         for (Future<Long> future : list) {
  26.             try {
  27.                 System.out.println("Total is: " + future.get());
  28.             } catch (InterruptedException e) {
  29.                 e.printStackTrace();
  30.             } catch (ExecutionException e) {
  31.                 e.printStackTrace();
  32.             }
  33.         }
  34.         executor.shutdown();
  35.     }
  36. }
  37.  
  38. class MyCallable implements Callable<Long> {
  39.     @Override
  40.     public Long call() throws Exception {
  41.         long sum = 0;
  42.         for (long i = 0; i < 100; i++) {
  43.             sum += i;
  44.         }
  45.         return sum;
  46.     }
  47.  
  48. }

slds;

nup_
  #4 (permalink)  
Antiguo 02/04/2014, 11:00
Avatar de rgf1987  
Fecha de Ingreso: diciembre-2012
Ubicación: Asturias
Mensajes: 269
Antigüedad: 11 años, 3 meses
Puntos: 22
Respuesta: Duda Ejecución Hilos

Buenas

gracias por la aclaración nup_, el tema de Futures, Callables y Executors, no entra en la certificación que estoy preparando, así que demomento me lo apunto, pero lo dejo para más adelante jeje.

Etiquetas: clase, hilos
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 11:21.