2010-03-26 18 views
7

Estoy escribiendo un código que engendrará dos hilos y luego esperará que se sincronicen usando la clase CyclicBarrier. El problema es que la barrera cíclica no está funcionando como se esperaba y el hilo principal no espera a que terminen los hilos individuales. Así es como se ve mi código:¿Cómo consigo que java.concurrency.CyclicBarrier funcione como se espera?

class mythread extends Thread{ 
    CyclicBarrier barrier; 
    public mythread(CyclicBarrier barrier) { 
     this.barrier = barrier; 
     } 

    public void run(){ 
      barrier.await(); 
     } 
} 



class MainClass{ 
public void spawnAndWait(){ 
    CyclicBarrier barrier = new CyclicBarrier(2); 
    mythread thread1 = new mythread(barrier).start(); 
    mythread thread2 = new mythread(barrier).start(); 
    System.out.println("Should wait till both threads finish executing before printing this"); 
    } 
} 

¿Alguna idea de lo que estoy haciendo mal? ¿O hay una mejor manera de escribir estos métodos de sincronización de barrera? Por favor ayuda.

Respuesta

14

Durante la ejecución de su ma en el hilo, crea otros dos hilos y les dice que esperen el uno al otro. Pero no escribió nada para que su hilo principal los aguarde y se queje de que no espera. Pruebe

CyclicBarrier barrier = new CyclicBarrier(3); 
mythread thread1 = new mythread(barrier).start(); 
mythread thread2 = new mythread(barrier).start(); 
barrier.await(); // now you wait for two new threads to reach the barrier. 
System.out.println("Should wait till both threads finish executing before printing this"); 

BTW. No extienda la clase Thread a menos que sea necesario. Implementa Runnable y pasa implementaciones a Thread objects. De esta manera:

class MyRunnable implements Runnable { 
    public void run(){ 
     // code to be done in thread 
    } 
} 

Thread thread1 = new Thread(MyRunnable); 
thread1.start(); 

EDITAR
Justificación para evitar que se extiende del hilo.
La regla de oro es el menor acoplamiento posible. La herencia es una conexión muy fuerte entre clases. Debe heredar de Thread si desea cambiar parte de su comportamiento predeterminado (es decir, anular algunos métodos) o si desea acceder a algunos campos protegidos de la clase Thread. Si no lo deseas, eliges un acoplamiento más flexible: implementa Runnable y lo pasa como un parámetro constructor a la instancia Thread.

+0

Sin embargo, esto lo hace sincrónico, mientras que OP parece querer un enfoque verdaderamente asincrónico. –

+1

@Chandru: Bueno, o bien "Debería esperar a que ambos subprocesos terminen de ejecutarse antes de imprimir esto" o asíncrono. No puedes esperar asincrónicamente. –

+0

Si lo entiendo correctamente, lo que necesita es imprimir esa línea después de que los 2 hilos completen su trabajo, lo que se puede lograr al hacerlo en la acción de barrera. De esta forma, si hay otras operaciones en el hilo actual que no dependen de la finalización de los otros 2 hilos, pueden continuar. Por cierto, yo no fui el que votó por ti. Todavía es una solución válida si todas las demás operaciones en el hilo actual dependían de la finalización de los 2 hilos. –

2

Pase una instancia Runnable al constructor de su CyclicBarrier de esta manera.

CyclicBarrier barrier = new CyclicBarrier(2, new Runnable() { 

    @Override 
    public void run() { 
     System.out.println("Should wait till both threads finish executing before printing this"); 
    } 
}); 

new mythread(barrier).start(); 
new mythread(barrier).start(); 
+0

Todavía no espera a que los dos programas finalicen antes de salir. ¿Hay alguna manera explícita de decir, esperar hasta que terminen tanto thread1 como thread2? –

+0

Sí, puedo hacer. Thread.join() está ahí para eso. – malaverdiere

+0

Si desea una espera verdaderamente asíncrona para la finalización de los hilos, ¿por qué molestarse si el método finaliza antes de completarse? En general, querrá hacer algo cuando ambos hilos terminen la ejecución.Simplemente ponga eso en la devolución de llamada a CyclicBarrier y ya está listo. –

2

Usted está buscando Thread.join() método ...

thread1.join(); 
thread2.join(); 
System.out.println("Finished"); 

EDIT: debido a los comentarios ...

Y si usted no quiere esperar para siempre que pueda también especifique la cantidad máxima de milisegundos más nanosegundos para esperar a que el hilo muera

+0

Pero esto es complicado porque si thread1.join() no ocurre, entonces thread2.join() esperará infinitamente. La razón por la que elegí CyclicBarrier es porque parece realmente asíncrono en su espera. –

+1

@Ritesh, pero si thread1.join no va a suceder para lo que estás esperando, entonces? ¿Cuál es tu uso? ¿necesita una implementación "CUALQUIERA thread1 or thread2 finished"? pgras muestra cómo implementar 'esperar hasta que ambos terminen' – Karussell

+1

@Ritesh, o desea esperar a que salgan tanto 'thread1' como' thread2' (en cuyo caso esta respuesta es correcta), o no (en cuyo caso el la versión en la pregunta es correcta.) – finnw

1

La barrera cíclica no es la elección correcta en este caso. Debe usar CountDownLatch aquí.

Supongo que está invocando el método spawnAndWait del método principal.

La razón por la que esto no funciona es que el CyclicBarrier tiene 2 constructores. Para realizar post-operaciones, debe usar un constructor de 2 parámetros. Lo más importante que debe recordar es que el hilo principal no esperará por el método await; pero continuará ejecutándose. Sin embargo, el subproceso especificado en el constructor CyclicBarrier solo se ejecutará cuando todos los subprocesos generados se detengan en la barrera (por el método await)

Cuestiones relacionadas