2011-06-09 11 views
5

Tengo una clase que genera un montón de hilos y tiene que esperar hasta que se completen todos los hilos generados. (Necesito calcular el tiempo para completar todos los hilos).Java: Multithreading -Wait/notifyToda la pregunta

MainClass genera todos los hilos y luego comprueba si todos los hilos se completan antes de que pueda llamarse a sí mismo completado.

Funcionará esta lógica. Si es así, ¿hay una mejor manera de hacer esto? Si no, me gustaría entender mejor este escenario.

class MainClass{ 
    private boolean isCompleted; 
    ... 
    for(task : tasks){ 
     threadpool.execute(task); 
    } 

    for(task : tasks){ 
     if(!task.isCompleted()){ 
      task.wait() 
     } 
    } 

    isCompleted = true; 
} 


class Task{ 
    public void run(){ 
     .... 
     .... 
     synchronized(this){ 
      task.completed = true; 
      notifyAll(); 
     } 
    } 
} 
+1

Creo que su código no funciona porque olvidó un bloque 'sincronizado' alrededor de' wait() '. Vea mi respuesta para una solución mejor (más rápida). –

+0

¡Impresionante! Exactamente lo que estaba buscando. Necesito al menos 5 minutos. Antes de que pueda cerrar esto. :) –

Respuesta

11

notifyAll() es relativamente lento. Una mejor manera es utilizar CountDownLatch:

import java.util.concurrent.CountDownLatch; 

int n = 10; 
CountDownLatch doneSignal = new CountDownLatch(n); 
// ... start threads ... 
doneSignal.await(); 

// and within each thread: 
doWork(); 
doneSignal.countDown(); 
+1

+1, aunque no explicó por qué 'CountDownLatch' sería una mejor opción, que no sea arbitraria (e implícitamente) decir que es más rápido que un esquema de notificación de espera. – mre

+1

Tengo una pregunta. Si la cuenta regresiva nunca llega a 0. ¿se bloqueará el hilo? –

+0

@Vanchinathan Chandrasekaran Sí. –

4

No hay necesidad de esperar/notificará en este caso. Puede simplemente recorrer los hilos y llamar al join(). Si el hilo ya está terminado, el hilo de MainClass simplemente esperará al siguiente.

Es posible que desee echar un vistazo a las utilidades de nivel superior en el paquete java.util.concurrent también.

+0

+1, por mencionar una solución simple (es decir, 'Thread.join()') y por referirse al paquete 'java.util.concurrent' como una mejor alternativa. – mre

4

Todo esto se puede hacer mediante java.util.concurrent.ExecutorService.

class MainClass { 
    ... 
    ExecutorService executor = Executors.newCachedThreadPool(); 
    List<Callable> tasks = ...; // prepare your tasks 

    // this invokes all tasks in parallel and waits until all are done 
    executor.invokeAll(tasks); 
    ... 
} 

Eso es todo.

+0

Acabo de probar eso y el programa se ejecutó un tiempo después de 'invokeAll'. Descubrí que debes llamar a 'executor.shutdown();', que libera todos los hilos y el programa puede finalizar de inmediato. –