2010-03-12 19 views
18

En mi programa, estoy creando varios hilos en el método main(). La última línea en el método principal es una llamada a System.out.println(), que no deseo llamar hasta que todos los hilos hayan desaparecido. He intentado llamar a Thread.join() en cada hilo, sin embargo, que bloquea cada hilo para que se ejecuten secuencialmente en lugar de en paralelo.¿Cómo pongo en pausa main() hasta que todos los demás hilos han muerto?

¿Hay alguna manera de bloquear el hilo principal() hasta que todos los otros hilos hayan terminado de ejecutarse? Aquí está la parte relevante de mi código:

public static void main(String[] args) { 

//some other initialization code 

//Make array of Thread objects 
Thread[] racecars = new Thread[numberOfRaceCars]; 

//Fill array with RaceCar objects 
for(int i=0; i<numberOfRaceCars; i++) { 
    racecars[i] = new RaceCar(laps, args[i]); 
} 

//Call start() on each Thread 
for(int i=0; i<numberOfRaceCars; i++) { 
    racecars[i].start(); 
    try { 
     racecars[i].join(); //This is where I tried to using join() 
          //It just blocks all other threads until the current        
          //thread finishes. 
    } catch(InterruptedException e) { 
     e.printStackTrace(); 
    } 
} 

//This is the line I want to execute after all other Threads have finished 
System.out.println("It's Over!"); 

} 

Gracias por la ayuda chicos!

Eric

Respuesta

39

Inicia sus hilos y espera a que terminen de inmediato (usando join()). En su lugar, usted debe hacer lo join() fuera del bucle en el otro bucle para, por ejemplo .:

// start all threads 
for(int i=0; i<numberOfRaceCars; i++) { 
    racecars[i].start(); 
} 
// threads run... we could yield explicity to allow the other threads to execute 
// before we move on, all threads have to finish 
for(int i=0; i<numberOfRaceCars; i++) { 
    racecars[i].join(); // TODO Exception handling 
} 
// now we can print 
System.out.println("It's over!"); 
+0

¡Agradable, eso funcionó maravillosamente! ¡Gracias! – ericso

+3

Este es obviamente el camino correcto a seguir. No puedo creer que las otras respuestas que abogan por el uso de wait() y notify() y las barreras se hayan subido de categoría: son demasiado complicadas para esta situación. –

+0

@AdrianPronk: Esa es la belleza de las diferentes opiniones. – Thomas

2

Usted podría wait() en el hilo principal y tienen todas las discusiones emiten una notifyAll() y cuando estén listas. Luego, cada vez que el hilo principal se despierta de esa manera, puede verificar si hay al menos un hilo que todavía está vivo, en cuyo caso wait() un poco más.

+0

Todavía estoy aprendiendo de programación Java, por lo que no entiendo por completo la sincronización y el objeto monitores todavía. Voy a investigar esto. ¡Gracias! – ericso

+1

@thechiman: si tiene algo de tiempo libre en sus manos, también puede estudiar el paquete java.util.concurrent que proporciona algunas formas bastante poderosas para la concurrencia más allá de los hilos de "bajo nivel". – Thomas

+0

Lo comprobaré también. Gracias. – ericso

0

Se podría hacer la última línea sea en un "seguimiento" hilo. Comprobaría de vez en cuando que es el único hilo en ejecución y algún estado de finalización == true y luego podría disparar si lo fuera. Entonces podría hacer otras cosas además de solo println

1

Puede usar el método de unión. Consulte la documentación here

+0

Él ya usa join. – middus

5

Se puede compartir un objeto CyclicBarrier entre sus RaceCar s y el hilo principal, y tienen los hilos invocan RaceCarawait() tan pronto como se hacen con su tarea. Construya la barrera con el número de hilos RaceCar más uno (para el hilo principal). El hilo principal continuará cuando todos los RaceCar hayan terminado. Ver http://java.sun.com/javase/6/docs/api/java/util/concurrent/CyclicBarrier.html

En detalle, construir un CyclicBarrier en el hilo principal, y añadir una llamada barrier.await() en su clase RaceCar justo antes de las salidas run() método, también añadir una llamada barrier.await() antes de la System.out.println() llamada en su hilo principal.

+0

Voy a comprobar esto también, gracias por la ayuda. – ericso

+0

Acabo de ver que Java tiene una clase llamada "java.util.concurrent.CountDownLatch" dedicada a ese problema, que funciona de manera similar a la barrera, pero permite que los subprocesos terminen inmediatamente cuando terminan ofreciendo un método llamado "cuenta regresiva()". –

+0

@ the-banana-king: +1 ... La ventaja de las barreras cíclicas y/o los cierres de cuenta atrás, etc. es que son técnicas de concurrencia bien conocidas y * no * idiosincrasia de Java que requieren un conocimiento profundo de las características específicas de Java poco interesantes. Los libros como * "Concurrencia de Java en la práctica" * recomiendan evitar los detalles de bajo nivel (Java) y buscar abstracciones/soluciones de mayor nivel. – SyntaxT3rr0r

1

Puede agregar un gancho de apagado para el mensaje "Se acabó". De esta manera, se producirá cuando el programa finalice y no tendrá que esperar cada hilo.

0

manera más simple

while (Thread.activeCount() > 1) { 
} 

sé que bloquean hilo principal ... pero funciona perfectamente!

0

probar este ejemplo:

public class JoinTest extends Thread { 

    public static void main(String[] args) 
    { 
     JoinTest t = new JoinTest(); 
     t.start(); 

     try { 

      t.join(); 
      int i = 0; 
      while(i<5) 
      { 
       System.out.println("parent thread is running......" +i++); 
      } 

     } catch (Exception e) { 
      // TODO: handle exception 
     } 


    } 


    public void run() 
    { 

     try { 

      int i =0; 
      while(i<5) 
      { 
       System.out.println("child thread running ........." +i++); 
      } 

     } catch (Exception e) { 
      // TODO: handle exception 
     } 
    } 
} 
+0

Explique por qué esto debería funcionar; consulte [cómo responder] (http://stackoverflow.com/help/how-to-answer). – agold

0

Seguro que tiene mejores opciones si vas para ExecutorService o ThreadPoolExecutor marco.

  1. invokeAll

    ejecuta las tareas encomendadas, devolviendo una lista de futuros que sostienen su estado y los resultados cuando todos completos. Future.isDone() es verdadero para cada elemento de la lista devuelta. Tenga en cuenta que una tarea completa puede haber terminado normalmente o lanzando una excepción. Los resultados de este método no están definidos si la colección dada se modifica mientras esta operación está en progreso. Parámetros Tipo:

  2. CountDownLatch: Inicializar CountDownLatch con contador como el número de hilos. Use countDown() y await() API y espere que el contador se convierta en cero.

Otras referencias:

How to use invokeAll() to let all thread pool do their task?

How is CountDownLatch used in Java Multithreading?

Cuestiones relacionadas