2011-12-23 3 views
6

Mirando los javadocs para CyclicBarrier encontré la siguiente declaración en la documentación de clase que no entiendo completamente. Desde el javadoc:Elección de un subproceso para la ejecución de acción de barrera - Java CyclicBarrier

Si el efecto de barrera no se basa en las partes sea suspendido cuando se ejecuta, a continuación, cualquiera de los hilos en el partido podría ejecutar esa acción cuando es liberado. Para facilitar esto, cada invocación de await() devuelve el índice de llegada de ese hilo en la barrera. A continuación, puede elegir cuál de ellos hay ejecutar la acción de barrera, por ejemplo:

if (barrier.await() == 0) { 
    // log the completion of this iteration 
} 

Puede alguien explicar cómo designar un hilo específico para la ejecución de la acción de barrera una vez que todas las partes han llamado .await() y tal vez proporcionar un ejemplo?

+0

Supongo que el hilo que especifique como hilo de "acción" procesará el código adicional justo después de que todos los hilos hayan terminado y comenzarán a ejecutarse después de 'barrier.await()'. Eso es bastante peligroso porque debe asegurarse de que los otros hilos (que se están ejecutando) no toquen los datos manipulados por el código de "acción". – toto2

Respuesta

1

CyclicBarrier permite la designación de un hilo por orden:

La designación de un hilo que vuelve a un fin específico es posible si, como usted dice, se encierra la lógica conclusión de barrera en una condicional que es específico de un hilo índice. Por lo tanto, su implementación anterior funcionará de acuerdo con la documentación que citó.

Sin embargo, el punto de confusión aquí es que la documentación está hablando de identidad de subprocesos en términos de orden de retorno a la barrera, en lugar de identidad de objeto de subprocesos. Por lo tanto, el hilo 0 se refiere al 0º hilo para completar.

Alternativa: designación de un subproceso con otros mecanismos.

Si desea tener un hilo específico en una acción específica después de que se completen otros trabajos, puede usar un mecanismo diferente, como un semáforo, por ejemplo. Si desea este comportamiento, puede que realmente no necesite la barrera cíclica.

Para inspeccionar qué significa la documentación, ejecute la clase (modificada desde http://programmingexamples.wikidot.com/cyclicbarrier) a continuación, donde he incorporado su fragmento.

Ejemplo de lo que se entiende por la documentación para el CyclicBarrier

hilo paquete; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample 
{ 
    private static int matrix[][] = 
    { 
     { 1 }, 
     { 2, 2 }, 
     { 3, 3, 3 }, 
     { 4, 4, 4, 4 }, 
     { 5, 5, 5, 5, 5 } }; 

    static final int rows = matrix.length; 
    private static int results[]=new int[rows]; 


    static int threadId=0; 
    private static class Summer extends Thread 
    { 
     int row; 

     CyclicBarrier barrier; 

     Summer(CyclicBarrier barrier, int row) 
     { 
      this.barrier = barrier; 
      this.row = row; 
     } 

     public void run() 
     { 
      int columns = matrix[row].length; 
      int sum = 0; 
      for (int i = 0; i < columns; i++) 
      { 
       sum += matrix[row][i]; 
      } 
      results[row] = sum; 
      System.out.println("Results for row " + row + " are : " + sum); 
      // wait for the others 
      // Try commenting the below block, and watch what happens. 
      try 
      { 
       int w = barrier.await(); 
       if(w==0) 
       { 
        System.out.println("merging now !"); 
        int fullSum = 0; 
        for (int i = 0; i < rows; i++) 
        { 

         fullSum += results[i]; 
        } 
        System.out.println("Results are: " + fullSum); 
       } 
      } 
      catch(Exception e) 
      { 
       e.printStackTrace(); 
      } 
     } 
    } 
    public static void main(String args[]) 
    { 
     /* 
     * public CyclicBarrier(int parties,Runnable barrierAction) 
     * Creates a new CyclicBarrier that will trip when the given number 
     * of parties (threads) are waiting upon it, and which will execute 
     * the merger task when the barrier is tripped, performed 
     * by the last thread entering the barrier. 
     */ 
     CyclicBarrier barrier = new CyclicBarrier(rows); 
     for (int i = 0; i < rows; i++) 
     { 
      System.out.println("Creating summer " + i); 
      new Summer(barrier, i).start(); 

     } 
     System.out.println("Waiting..."); 
    } 
} 
+0

Si tengo 'CyclicBarrierExample' como uno de los bean en primavera y' static results [] 'está asociado con la clase, y se comparte entre varios hilos debido al comportamiento del almacenamiento en caché en JVM. ¿No sería esto un problema? –

3

bien, pretender RuPaul quería algunos subprocesos de trabajo, pero sólo el tercero que terminó se supone que debe hacer la tarea de barrera (Di "Sashay, Chante").

import java.util.Random; 
import java.util.concurrent.BrokenBarrierException; 
import java.util.concurrent.CyclicBarrier; 
import java.util.concurrent.TimeUnit; 

public class Main 
{ 

    private static class Worker implements Runnable { 

     private CyclicBarrier barrier; 

     public Worker(CyclicBarrier b) { 
     barrier = b; 
     } 

     public void run() { 
     final String threadName = Thread.currentThread().getName(); 

     System.out.printf("%s: You better work!%n", threadName); 
     // simulate the workin' it part 
     Random rnd = new Random(); 
     int secondsToWorkIt = rnd.nextInt(10) + 1; 

     try { 
      TimeUnit.SECONDS.sleep(secondsToWorkIt); 
     } catch (InterruptedException ex) { /* ...*/ } 

     System.out.printf("%s worked it, girl!%n", threadName); 

     try { 
      int n = barrier.await(); 
      final int myOrder = barrier.getParties() - n; 
      System.out.printf("Turn number: %s was %s%n", myOrder, threadName); 

      // MAGIC CODE HERE!!! 
      if (myOrder == 3) { // the third one that finished 
       System.out.printf("%s: Sashay Chante!%n", myOrder); 
      } 
      // END MAGIC CODE 
     } 
     catch (BrokenBarrierException ex) { /* ... */ } 
     catch (InterruptedException ex) { /* ... */ } 
     } 
    } 

    private final int numThreads = 5; 

    public void work() { 
     /* 
     * I want the 3rd thread that finished to say "Sashay Chante!" 
     * when everyone has called await. 
     * So I'm not going to put my "barrier action" in the CyclicBarrier constructor, 
     * where only the last thread will run it! I'm going to put it in the Runnable 
     * that calls await. 
     */ 
     CyclicBarrier b = new CyclicBarrier(numThreads); 

     for (int i= 0; i < numThreads; i++) { 
     Worker task = new Worker(b); 
     Thread thread = new Thread(task); 
     thread.start(); 
     } 
    } 

    public static void main(String[] args) 
    { 
     Main main = new Main(); 
     main.work(); 
    } 

} 

Aquí es un ejemplo de la salida:

Thread-0: You better work! 
Thread-4: You better work! 
Thread-2: You better work! 
Thread-1: You better work! 
Thread-3: You better work! 
Thread-1 worked it, girl! 
Thread-4 worked it, girl! 
Thread-0 worked it, girl! 
Thread-3 worked it, girl! 
Thread-2 worked it, girl! 
Turn number: 5 was Thread-2 
Turn number: 3 was Thread-0 
3: Sashay Chante! 
Turn number: 1 was Thread-1 
Turn number: 4 was Thread-3 
Turn number: 2 was Thread-4 

Como se puede ver, el hilo que terminó tercero era Tema-0, de modo Tema-0 fue el que hizo el "efecto de barrera ".

Diga que es capaz de nombrar sus hilos:

thread.setName("My Thread " + i); 

continuación, puede realizar la acción en el hilo de ese nombre ... No sé qué tan factible es para usted.

+1

Fantástico ejemplo. ¿Alguien ha visto mi DVD Birdcage? –

2

Creo que la sección de la documentación es sobre una alternativa a la acción de barrera Runnable, no una forma particular de usarlo. Tenga en cuenta cómo se dice (el énfasis es mío):

Si el efecto de barrera no se basa en las partes que se suspendió cuando se ejecuta

Si especifica un efecto de barrera como un ejecutable, a continuación, que ...

se ejecuta una vez por cada punto de la barrera, después de que el último hilo en el grupo llega, pero antes de que los hilos se liberan

Por lo tanto, mientras que los hilos están suspendidos (aunque dado que es ejecutado por el último hilo que llega, ese no está suspendido; pero al menos su flujo normal de ejecución se suspende hasta que finaliza la acción de barrera).

El negocio sobre el uso del valor de retorno de await() es algo que puede hacer si no necesita ejecutar su acción mientras se suspenden los hilos.

Los ejemplos de la documentación son indicativos. El ejemplo que utiliza una acción de barrera Runnable coordina el trabajo de algunos otros hilos: fusionar las filas y verificar si el trabajo está terminado. Los otros hilos necesitan esperar a que sepa si tienen más trabajo por hacer. Entonces, tiene que funcionar mientras están suspendidos. El ejemplo que usa el valor de retorno desde await() es un poco de registro. Los otros hilos no dependen de que se haya realizado el registro. Entonces, puede suceder mientras los otros hilos han comenzado a hacer más trabajo.

Cuestiones relacionadas