Clase de subprocesos múltiples concurrentes de JAVA (1): comprensión y uso de CountDownLatch

Tabla de contenido

Concepto CountDownLatch

Uso de CountDownLatch

Deficiencias de CountDownLatch

Instrucciones de CountDownLatch (calculadora de cuenta regresiva)

Ejemplo de prueba uno:

Ejemplo de prueba dos:


Concepto CountDownLatch

CountDownLatch es una clase de herramienta de sincronización que se utiliza para coordinar la sincronización entre varios subprocesos o para comunicarse entre subprocesos (en lugar de servir como una exclusión mutua).

CountDownLatch permite que un hilo continúe ejecutándose después de esperar a que otros hilos completen su trabajo.

Utilice un contador para la implementación. El valor inicial del contador es el número de hilos. Cuando cada hilo completa su tarea,

El valor del contador disminuirá en uno. Cuando el valor del contador es 0, significa que todos los subprocesos han completado algunas tareas.

Luego, el hilo que espera en CountDownLatch puede reanudar la ejecución de la siguiente tarea.

Uso de CountDownLatch

Uso típico de CountDownLatch:

1. Cierto subproceso espera a que n subprocesos terminen de ejecutarse antes de comenzar a ejecutarse. Inicialice el contador de CountDownLatch a un nuevo CountDownLatch (n) y disminuya el contador en 1 cada vez que un subproceso de tarea termine de ejecutar countdownLatch.countDown (). Cuando el valor del contador sea 0, el subproceso de await () en CountDownLatch Se despertó. Un escenario de aplicación típico es que cuando se inicia un servicio, el subproceso principal debe esperar a que se carguen varios componentes antes de continuar.

2. Obtenga el máximo paralelismo cuando varios subprocesos comiencen a ejecutar tareas. Tenga en cuenta que se trata de paralelismo, no de simultaneidad. Enfatiza que varios hilos comienzan a ejecutarse al mismo tiempo. Al igual que en una carrera, se colocan varios hilos en el punto de partida, esperando a que suene el pistoletazo de salida y luego se ejecutan al mismo tiempo. El método es inicializar un CountDownLatch (1) compartido, inicializar su contador en 1, varios subprocesos primero countdownlatch.await () antes de comenzar a realizar tareas, cuando el subproceso principal llama a countDown (), el contador se convierte en 0 y varios subprocesos Se despertó al mismo tiempo.

Deficiencias de CountDownLatch

CountDownLatch es de una sola vez. El valor de la calculadora solo se puede inicializar una vez en el constructor, y no hay ningún mecanismo para establecer el valor nuevamente después. Después de que CountDownLatch se agota, no se puede volver a usar.

Instrucciones de CountDownLatch (calculadora de cuenta regresiva)

Descripción del método

countDown vacío público ()

  Disminuya la cuenta del pestillo, si la cuenta llega a cero, suelte todos los hilos en espera. Si el recuento actual es mayor que cero, el recuento se reducirá.

espera booleana pública (tiempo de espera prolongado, unidad TimeUnit) lanza InterruptedException

  Hace que el subproceso actual espere hasta que el pestillo llegue a cero, a menos que el subproceso se interrumpa o se exceda el tiempo de espera especificado. Si el recuento actual es cero, este método devuelve inmediatamente un valor verdadero.

  Si el recuento actual es mayor que cero, el subproceso actual se desactivará para fines de programación del subproceso, y el subproceso permanecerá inactivo hasta que ocurra una de las siguientes tres situaciones:

  Debido a que se llama al método countDown (), la cuenta llega a cero, o algún otro hilo interrumpe el hilo actual, o el tiempo de espera especificado ha expirado.

  • Si el recuento llega a cero, el método devuelve un valor verdadero.
  • Si el subproceso actual ya ha establecido el estado interrumpido del subproceso al ingresar a este método; o se interrumpe mientras espera, se lanza una InterruptedException y se borra el estado interrumpido del subproceso actual.
  • Si se excede el tiempo de espera especificado, el valor devuelto es falso. Si el tiempo es menor o igual a cero, el método no esperará en absoluto.

parámetro:

  tiempo de espera: el tiempo más largo para esperar

  unidad-tiempo de espera del parámetro unidad de tiempo

regreso:

  Si el recuento llega a cero, devuelve verdadero; si el tiempo de espera transcurre antes de que el recuento llegue a cero, devuelve falso

Lanza:

  InterruptedException: si el hilo actual se interrumpe mientras espera

 

Ejemplo de prueba uno:

  El hilo principal espera a que la ejecución del hilo secundario se complete en ejecución

package com.example.demo.CountDownLatchDemo;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 主线程等待子线程执行完成再执行
 */
public class CountdownLatchTest1 {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(3);
        final CountDownLatch latch = new CountDownLatch(3);
        for (int i = 0; i < 3; i++) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("子线程" + Thread.currentThread().getName() + "开始执行");
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("子线程"+Thread.currentThread().getName()+"执行完成");
                        latch.countDown();//当前线程调用此方法,则计数减一
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            service.execute(runnable);
        }

        try {
            System.out.println("主线程"+Thread.currentThread().getName()+"等待子线程执行完成...");
            latch.await();//阻塞当前线程,直到计数器的值为0
            System.out.println("主线程"+Thread.currentThread().getName()+"开始执行...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Ejemplo de prueba dos:

Para la carrera de 100 metros, 4 atletas llegaron al campo y esperaron la contraseña del árbitro. El árbitro dio la orden y los jugadores comenzaron a correr al mismo tiempo. Cuando todos los jugadores llegaron a la línea de meta, el árbitro hizo una clasificación resumida.

package com.sapdev.hook;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {
    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();
        final CountDownLatch cdOrder = new CountDownLatch(1);
        final CountDownLatch cdAnswer = new CountDownLatch(4);
        for (int i = 0; i < 4; i++) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("选手" + Thread.currentThread().getName() + "正在等待裁判发布口令");
                        cdOrder.await();
                        System.out.println("选手" + Thread.currentThread().getName() + "已接受裁判口令");
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("选手" + Thread.currentThread().getName() + "到达终点");
                        cdAnswer.countDown();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            service.execute(runnable);
        }
        try {
            Thread.sleep((long) (Math.random() * 10000));
            System.out.println("裁判"+Thread.currentThread().getName()+"即将发布口令");
            cdOrder.countDown();
            System.out.println("裁判"+Thread.currentThread().getName()+"已发送口令,正在等待所有选手到达终点");
            /**
			 * [依次环形同步当前任务,否则造成线程错乱执行/监测子线程的执行同步]
			 * [await()进行等待,当计数减到0时,所有线程并行执行]
			 * 注意:cdAnswer此处需要等待释放,即使上面的count已经为0了,此处需要再次尝试阻塞,如果上面为0状态,所以本次阻塞是无效的
			 */
            cdAnswer.await();
            System.out.println("所有选手都到达终点");
            System.out.println("裁判"+Thread.currentThread().getName()+"汇总成绩排名");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        service.shutdown();
    }
}

 

Supongo que te gusta

Origin blog.csdn.net/bj_chengrong/article/details/108703895
Recomendado
Clasificación