2011-12-23 18 views
6

Guardando i javadocs per CyclicBarrier ho trovato la seguente dichiarazione nella documentazione di classe che non capisco completamente. Dal javadoc:Eletto un thread per l'esecuzione di azioni barriera - Java CyclicBarrier

Se l'azione di barriera non si basa su parti di essere sospeso quando viene eseguita, allora qualsiasi dei fili nel partito potrebbe eseguire l'azione quando viene rilasciato. Per facilitare questo, ogni invocazione di await() restituisce l'indice di arrivo di quel thread alla barriera. È quindi possibile scegliere quale thread dovrebbe eseguire l'azione di barriera, ad esempio:

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

Qualcuno può spiegare come designare uno specifico thread per l'esecuzione dell'azione di barriera una volta che tutti i partiti hanno chiamato .await() e forse fornire un esempio?

+0

Direi che il thread specificato come thread "action" elaborerà il codice extra subito dopo aver eseguito tutti i thread e inizieranno l'esecuzione dopo 'barrier.await()'. Questo è abbastanza pericoloso perché devi assicurarti che gli altri thread (attualmente in esecuzione) non tocchino i dati manipolati dal codice di "azione". – toto2

risposta

1

CyclicBarrier consente designa una filettatura per ordine:

Designazione di un filo che restituisce in un ordine specifico è possibile se, come dici, si racchiude la logica completamento barriera in una condizione che è specifico per un thread indice. Pertanto, la tua implementazione sopra funzionerà in base alla documentazione che hai citato.

Tuttavia, il punto di confusione qui - è che la documentazione parla dell'identità di thread in termini di ordine di ritorno alla barriera, piuttosto che l'identità dell'oggetto di thread. Pertanto, il thread 0 si riferisce alla stringa 0th da completare.

Alternativa: designazione di una filettatura utilizzando altri meccanismi.

Se si desidera che una determinata discussione esegua un'azione specifica dopo che altri lavori sono stati completati, è possibile utilizzare un meccanismo diverso, ad esempio un semaforo. Se hai desiderato questo comportamento, potresti non aver davvero bisogno della barriera ciclica.

Per verificare cosa si intende per documentazione, eseguire la classe (modificata da http://programmingexamples.wikidot.com/cyclicbarrier) in basso, dove è stato incorporato lo snippet.

Esempio di ciò che si intende con la documentazione per il CyclicBarrier

filo pacchetto; importazione 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

Se in primavera ho 'CyclicBarrierExample' come uno dei bean e' i risultati statici [] 'sono associati alla classe e condivisi su più thread a causa del comportamento della memorizzazione nella cache in JVM. Questo non sarebbe un problema? –

3

OK, finta RuPaul ha voluto alcuni thread di lavoro, ma si suppone che solo il 3 ° uno che finito di fare il compito di barriera (Dire "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(); 
    } 

} 

Ecco un esempio di output:

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 

Come si può vedere, il filo rosso che è arrivato 3 ° era Thread-0, in modo da Thread-0 è stato quello che ha fatto "l'azione di barriera ".

dici di essere in grado di nominare i thread:

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

Quindi è possibile eseguire l'azione sul filo di quel nome ... io non so come fattibile che è per voi.

+1

Fantastico esempio. Qualcuno ha visto il mio DVD Birdcage? –

2

Penso che la sezione della documentazione sia relativa a alternativa all'azione di barriera Runnable, non un modo particolare di utilizzarlo. Si noti come si dice (sottolineatura mia):

Se l'azione di barriera non si basa su parti di sospensione quando viene eseguita

Se si specifica un'azione di barriera come un eseguibile, allora si ...

viene eseguito una volta per ogni punto di barriera, dopo l'ultimo filo nel partito arriva, ma prima di qualsiasi thread vengono rilasciati

Quindi, mentre i thread sono sospesi (anche se poiché è eseguito dall'ultimo thread per arrivare, quello non è sospeso; ma almeno il suo normale flusso di esecuzione è sospeso fino al termine dell'azione di barriera).

L'attività sull'utilizzo del valore di ritorno di await() è un'operazione che è possibile eseguire se non è necessario eseguire l'azione mentre i thread sono sospesi.

Gli esempi della documentazione sono indicativi. L'esempio che utilizza un'azione di barriera Runnable sta coordinando il lavoro di alcuni altri thread: unendo le righe e controllando se il lavoro è stato eseguito. Gli altri thread devono attendere per sapere se hanno più lavoro da fare. Quindi, deve essere eseguito mentre sono sospesi. L'esempio che utilizza il valore restituito da await() è una registrazione. Gli altri thread non dipendono dal fatto che la registrazione sia stata eseguita. Quindi, può succedere mentre gli altri thread hanno iniziato a fare più lavoro.

Problemi correlati