Java.util.concurrent.CyclicBarrier en Java

CyclicBarrier se usa para hacer que los hilos se esperen unos a otros. Se usa cuando diferentes subprocesos procesan una parte del cálculo y cuando todos los subprocesos han completado la ejecución, el resultado debe combinarse en el subproceso principal. En otras palabras, CyclicBarrier se usa cuando varios subprocesos realizan diferentes subtareas y la salida de estas subtareas debe combinarse para formar la salida final. Después de completar su ejecución, los subprocesos llaman al método await() y esperan a que otros subprocesos alcancen la barrera. Una vez que todos los subprocesos han llegado, las barreras dan paso a los subprocesos para continuar.

Funcionamiento de CyclicBarrier

CyclicBarriers se definen en el paquete java.util.concurrent. Primero se crea una nueva instancia de CyclicBarriers especificando el número de subprocesos que deben esperar las barreras.

CyclicBarrier newBarrier = new CyclicBarrier(numberOfThreads);

Todos y cada uno de los subprocesos realizan algunos cálculos y, después de completar su ejecución, llaman a los métodos await() como se muestra:

public void run()
{
    // thread does the computation
    newBarrier.await();
}

Funcionamiento de CyclicBarrier:


Once the number of threads that called await() equals numberOfThreads, the barrier then gives a way for the waiting threads. The CyclicBarrier can also be initialized with some action that is performed once all the threads have reached the barrier. This action can combine/utilize the result of computation of individual thread waiting in the barrier.

Runnable action = ... 
//action to be performed when all threads reach the barrier;
CyclicBarrier newBarrier = new CyclicBarrier(numberOfThreads, action);

Métodos importantes de CyclicBarrier:

  1. getParties: Devuelve el número de partes necesarias para disparar esta barrera.
    Sintaxis:
    public int getParties()

    Devoluciones:
    el número de partes necesarias para disparar esta barrera

  2. reset: Restablece la barrera a su estado inicial.
    Sintaxis:
    public void reset()

    Devoluciones:
    void pero restablece la barrera a su estado inicial. Si alguna parte está esperando actualmente en la barrera, regresará con una BrokenBarrierException.

  3. isBroken: Consulta si esta barrera está rota.
    Sintaxis:
    public boolean isBroken()

    Devuelve:
    verdadero si una o más partes rompieron esta barrera debido a una interrupción o tiempo de espera desde la construcción o el último restablecimiento, o una acción de barrera falló debido a una excepción; falso en caso contrario.

  4. getNumberWaiting: Devuelve el número de personas que actualmente esperan en la barrera.
    Sintaxis:
    public int getNumberWaiting()

    Devuelve:
    el número de partes actualmente bloqueadas en await()

  5. await: Espera hasta que todas las partes hayan invocado await en esta barrera.
    Sintaxis:
    public int await() throws InterruptedException, BrokenBarrierException

    Devuelve:
    el índice de llegada del subproceso actual, donde el índice getParties() – 1 indica el primero en llegar y cero indica el último en llegar.

  6. await: Espera hasta que todas las partes hayan invocado await en esta barrera, o hasta que transcurra el tiempo de espera especificado.
    Sintaxis:
    public int await(long timeout, TimeUnit unit) 
    throws InterruptedException,
    BrokenBarrierException, TimeoutException

    Devuelve:
    el índice de llegada del hilo actual, donde el índice getParties() – 1 indica el primero en llegar y cero indica el último en llegar

//JAVA program to demonstrate execution on Cyclic Barrier
  
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
  
class Computation1 implements Runnable
{
    public static int product = 0;
    public void run()
    {
        product = 2 * 3;
        try
        {
            Tester.newBarrier.await();
        } 
        catch (InterruptedException | BrokenBarrierException e) 
        {
            e.printStackTrace();
        }
    }
}
  
class Computation2 implements Runnable
{
    public static int sum = 0;
    public void run()
    {
        // check if newBarrier is broken or not
        System.out.println("Is the barrier broken? - " + Tester.newBarrier.isBroken());
        sum = 10 + 20;
        try
        {
            Tester.newBarrier.await(3000, TimeUnit.MILLISECONDS);
          
            // number of parties waiting at the barrier
            System.out.println("Number of parties waiting at the barrier "+
            "at this point = " + Tester.newBarrier.getNumberWaiting());
        } 
        catch (InterruptedException | BrokenBarrierException e) 
        {
            e.printStackTrace();
        } 
        catch (TimeoutException e) 
        {
            e.printStackTrace();
        }
    }
}
  
  
public class Tester implements Runnable
{
    public static CyclicBarrier newBarrier = new CyclicBarrier(3);
      
    public static void main(String[] args)
    {
        // parent thread
        Tester test = new Tester();
          
        Thread t1 = new Thread(test);
        t1.start();
    }
    public void run()
    {
        System.out.println("Number of parties required to trip the barrier = "+
        newBarrier.getParties());
        System.out.println("Sum of product and sum = " + (Computation1.product + 
        Computation2.sum));
          
        // objects on which the child thread has to run
        Computation1 comp1 = new Computation1();
        Computation2 comp2 = new Computation2();
          
        // creation of child thread
        Thread t1 = new Thread(comp1);
        Thread t2 = new Thread(comp2);
          
        // moving child thread to runnable state
        t1.start();
        t2.start();
  
        try
        {
            Tester.newBarrier.await();
        } 
        catch (InterruptedException | BrokenBarrierException e) 
        {
            e.printStackTrace();
        }
          
        // barrier breaks as the number of thread waiting for the barrier
        // at this point = 3
        System.out.println("Sum of product and sum = " + (Computation1.product + 
        Computation2.sum));
                  
        // Resetting the newBarrier
        newBarrier.reset();
        System.out.println("Barrier reset successful");
    }
}

Producción:

<Number of parties required to trip the barrier = 3
Sum of product and sum = 0
Is the barrier broken? - false
Number of parties waiting at the barrier at this point = 0
Sum of product and sum = 36
Barrier reset successful

Explicación: el valor de (suma + producto) = 0 se imprime en la consola porque el subproceso secundario aún no se ejecutó para establecer los valores de la variable suma y producto. Después de esto, (suma + producto) = 36 se imprime en la consola porque los subprocesos secundarios se ejecutaron configurando los valores de suma y producto. Además, el número de subprocesos en espera en la barrera llegó a 3, por lo que la barrera permitió que pasaran todos los subprocesos y finalmente se imprimieron 36. El valor de “Número de partes esperando en la barrera en este punto” = 0 porque los tres subprocesos ya habían llamado al método await() y, por lo tanto, la barrera ya no está activa. Al final, newBarrier se restablece y se puede usar nuevamente.

BrokenBarrierException

Una barrera se rompe cuando cualquiera de los subprocesos en espera abandona la barrera. Esto sucede cuando se interrumpe uno o más subprocesos en espera o cuando se completa el tiempo de espera porque el subproceso llamó a los métodos await() con un tiempo de espera de la siguiente manera:

newBarrier.await(1000, TimeUnit.MILLISECONDS);
// thread calling this await() 
// methods waits for only 1000 milliseconds.

Cuando la barrera se rompe debido a uno o más subprocesos participantes, los métodos await() de todos los demás subprocesos lanzan una BrokenThreadException. Mientras que los subprocesos que ya están esperando en las barreras tienen su llamada await() terminada.

Diferencia entre CyclicBarrier y CountDownLatch

  • Un CountDownLatch se puede usar solo una vez en un programa (hasta que su cuenta llegue a 0).
  • Una CyclicBarrier se puede usar una y otra vez una vez que se liberan todos los subprocesos en una barrera.

Referencia: Oráculo

Este artículo es una contribución de Mayank Kumar . Si le gusta GeeksforGeeks y le gustaría contribuir, también puede escribir un artículo usando contribuya.geeksforgeeks.org o envíe su artículo por correo a contribuya@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.

Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *