Semáforo

Los semáforos generalmente se usan cuando es necesario limitar la cantidad de subprocesos cuando se trabaja con el sistema de archivos. El acceso a un archivo u otro recurso compartido se controla a través de un contador. Si su valor es mayor que cero, se permite el acceso, pero al mismo tiempo el contador disminuirá.

En el momento en que el contador devuelve cero, el subproceso actual se bloqueará hasta que otro subproceso libere el recurso. El número de parámetros de permisos debe establecerse a través del constructor.

Debe seleccionar este parámetro individualmente, según la potencia de su computadora o computadora portátil.

public class Main {

   public static void main(String[] args) {
       Semaphore sem = new Semaphore(1);
       CommonResource res = new CommonResource();
       new Thread(new MyThread(res, sem, "MyThread_1")).start();
       new Thread(new MyThread(res, sem, "MyThread_2")).start();
       new Thread(new MyThread(res, sem, "MyThread_3")).start();
   }
}

class CommonResource {
   int value = 0;
}

class MyThread implements Runnable {
   CommonResource commonResource;
   Semaphore semaphore;
   String name;
   MyThread(CommonResource commonResource, Semaphore sem, String name) {
       this.commonResource = commonResource;
       this.semaphore = sem;
       this.name = name;
   }

   public void run() {

       try {
           System.out.println(name + "waiting permission");
           semaphore.acquire();
           commonResource.value = 1;
           for (int i = 1; i < 7; i++) {
               System.out.println(this.name + ": " + commonResource.value);
               commonResource.value++;
               Thread.sleep(150);
           }
       } catch (InterruptedException e) {
           System.out.println(e.getMessage() + " " + name);
           Thread.currentThread().interrupt();
       }
       System.out.println(name + "releases permission");
       semaphore.release();
   }
}

CountDownLatch y otros

CountDownLatch : permite que varios subprocesos esperen hasta que se complete una cierta cantidad de operaciones realizadas en otros subprocesos. Un ejemplo es la instalación de una aplicación: no comenzará hasta que aceptes las condiciones de uso, hasta que selecciones una carpeta donde instalar un nuevo programa, etc. Hay un método especial countDown() para esto : este método reduce el contador de cuenta atrás en uno.

Tan pronto como el conteo llegue a cero, todos los subprocesos en espera en await continuarán con su trabajo, y todas las llamadas subsiguientes de await pasarán sin esperar. El contador de cuenta regresiva es un contador de una sola vez y no se puede restablecer.

CyclicBarrier : se utiliza para sincronizar un número determinado de subprocesos en un punto. La barrera se alcanza cuando N subprocesos llaman al método await(...) y se bloquean. Después de eso, el contador se restablece a su valor original y los subprocesos en espera se liberarán. Además, si es necesario, es posible ejecutar código personalizado antes de desbloquear subprocesos y restablecer el contador. Para ello, se pasa a través del constructor un objeto con una implementación de la interfaz Runnable .

Exchanger<V> : la clase Exchanger está diseñada para el intercambio de datos entre subprocesos. Se escribe y escribe el tipo de datos que los subprocesos necesitan intercambiar.

Los datos se intercambian utilizando el único método de intercambio () de esta clase :

V exchange(V x) throws InterruptedException
V exchange(V x, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException

El parámetro x representa el búfer de datos que se va a intercambiar. La segunda forma del método también define el parámetro de tiempo de espera , el tiempo de espera y la unidad , el tipo de unidad de tiempo que se usará para el parámetro de tiempo de espera .

La clase Phaser le permite sincronizar subprocesos que representan una sola fase o etapa en la ejecución de una acción general. Phaser define un objeto de sincronización que espera hasta que se complete una determinada fase. El Phaser luego pasa a la siguiente etapa o fase y espera a que se complete nuevamente.

Cuando se trabaja con la clase Phaser , es común crear primero su objeto. A continuación, debemos registrar a todos los participantes. Para registrar a cada participante, se llama al método register() , o puede prescindir de este método pasando el número requerido de participantes al constructor de Phaser .

Luego, cada participante realiza un determinado conjunto de acciones que componen la fase. Y el sincronizador Phaser espera hasta que todos los participantes hayan completado la ejecución de la fase. Para informar al sincronizador que la fase ha terminado, el participante debe llamar al métodoarribe () oarriveAndAwaitAdvance () . El sincronizador luego pasa a la siguiente fase.