Comprensión profunda de CyclicBarrier
Otros puntos de conocimiento
Comprensión profunda de los conceptos básicos de subprocesos múltiples de Java Comprensión profunda del
uso de aqs ReentrantLock
Comprensión profunda del semáforo Semáforo
Comprensión profunda de las tres características principales
de la concurrencia Comprensión profunda de la programación concurrente Comprensión profunda de CAS
En profundidad comprensión del conjunto de subprocesos Java CountDownLatch
Uso detallado de CyclicBarrier
Uso detallado de CyclicBarrier
Principio de Barrera Cíclica
Ejemplo de depuración para recorrer el proceso
El hilo del jugador t1 t2 y el hilo principal del árbitro están listos para el juego.
public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
new Thread(() -> {
try {
Thread.sleep(10_000);
System.out.println("t1 在准备 ");
cyclicBarrier.await(); // 等另外一个一个线程准备好 然后开始做事情
System.out.println("t1 准备好了 ");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
},"t1").start();
new Thread(() -> {
try {
Thread.sleep(5_000);
System.out.println("t2 在准备 ");
cyclicBarrier.await(); // 等另外一个一个线程准备好 然后开始做事情
System.out.println("t2 准备好了 ");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
},"t2" ).start();
System.out.println(" 裁判 在准备 ");
cyclicBarrier.await();
System.out.println(" 裁判 准备好了 ");
while (true){
if (cyclicBarrier.getNumberWaiting()==0){
System.out.println(" 时间到: 开始比赛");
return;
}
}
}
复制代码
resultado de la operación
debug ejecuta el hilo principal primero
sin tiempo de espera
método específicoprivate int dowait(boolean timed, long nanos)
Puede ver que ReentrantLock
el bloqueo , y el conteo se reduce en uno
Bloquear el hilo principal
Aquí el viaje es una cola condicional
private final Condition trip = lock.newCondition();
Puede ver que se crea un nodo de nodo condicional aquí
método addConditionWaiter
y luego LockSupport.park(this); bloquea el hilo actual
Puedes ver que el hilo principal ya está esperando, ahora vamos al hilo t1
Continúe siguiendo la lógica de cuenta regresiva anterior, en este momento el conteo aún no es igual a 0
Todavía tomará el método de cola condicional de espera
Crear un nuevo nodo de condición de nodo de subproceso y ponerlo en cola
luego sigue estacionando
Próximo hilo t2 en espera
Se encontrará que el recuento de subprocesos t2 es 0 en este momento, y se ejecuta el método nextGeneration();
¿El subproceso t2 actual ejecuta el método signalAll para notificar a todos?
cuenta = fiestas; poner a cero el contador
Introduzca el método, obtenga el nodo principal,
Ejecute el método doSignalAll (primero)
para obtener el nodo principal y establezca el siguiente puntero en el
método nulo transferForSignal
Se encuentra que el estado del nodo condicional se establece en 0 primero, y luego se crea un nuevo nodo NodoNode p = enq(node);
Nuevo nodo nodo
这段代码很熟悉,是aqs里构建同步队列
以及入队的方法,可以明白t2线程将条件队列里所有的节点转为同步队列
t2 最后执行unlock
释放锁
这里是也是aqs里的释放锁 逻辑,同时将获取锁的线程置为null
唤醒其他线程
将 Node 节点状态置为 0
唤醒main线程
此时main线程被t2唤醒
同理main线程这里也执行置为当前线程锁的线程未null
然后unLock
继续唤醒其他线层 这里是t1
这里还是这个方法,和上面逻辑一样 也是aqs里的
可以看到t1被唤醒,此时三个线程都被是唤醒状态
此时将main线程执行到这里
将t1执行到这里
将t2执行到这里
最后
CyclicBarrier 构造,count是计数器, parties 是备份的计数器,barrierCommand 是传进来的任务
在 await 方法里 dowait 时候可以看到 计数器是 0 了 可以执行这个方法,可以用来做执行结束通知
最后看重置方法
重置,以及通知
最后
实现原理
CyclicBarrier是通过ReentrantLock的"独占锁"和Conditon来实现一组线程的阻塞 唤醒的,而CountDownLatch则是通过AQS的“共享锁”实现
CyclicBarrier执行流程
大概范围的一个执行流程,没有那么细。
- 1 await() 先进行计数逻辑,然后将线程node节点放入条件队列
- 2 最后一个await() 计数为 0 时,该线程将条件队列转换为同步队列,然后唤醒下一个同步队列节点,也就是去唤醒下一个线程
- 3 其他线程被唤醒继续唤醒下一个线程,这里的流程和之前aqs流程是一样的,都是aqs里的逻辑。
都是在lock加锁和解锁里进行操作的
CyclicBarrier与CountDownLatch的区别
- 1 El contador de CountDownLatch solo se puede usar una vez, mientras que el contador de CyclicBarrier se puede restablecer con el método reset(). Por lo tanto, CyclicBarrier puede manejar escenarios comerciales más complejos, como si ocurre un error de cálculo, puede restablecer el contador y dejar que los subprocesos lo ejecuten nuevamente.
- 2 CyclicBarrier también proporciona getNumberWaiting (puede obtener el número de hilos bloqueados por CyclicBarrier), isBroken (usado para saber si el hilo bloqueado está interrumpido) y otros métodos.
- 3 CountDownLatch bloqueará el subproceso principal y CyclicBarrier no bloqueará el subproceso principal, solo bloqueará los subprocesos.
- 4 Tanto CountDownLatch como CyclicBarrier pueden realizar la espera entre subprocesos, pero tienen énfasis diferentes. CountDownLatch generalmente se usa para uno o más subprocesos, esperando que otros subprocesos completen la tarea antes de ejecutar. CyclicBarrier generalmente se usa para que un grupo de subprocesos se esperen unos a otros hasta cierto estado, y luego este grupo de subprocesos se ejecuta al mismo tiempo.
- 5 CyclicBarrier también puede proporcionar una barrierAction para combinar resultados de cálculos de subprocesos múltiples.
- 6 CyclicBarrier usa el "bloqueo exclusivo" de ReentrantLock y Conditon para realizar el bloqueo de activación de un grupo de subprocesos, mientras que CountDownLatch se implementa a través del "bloqueo compartido" de AQS.