In-depth understanding of CyclicBarrier
Other knowledge points
In-depth understanding of Java multi-threading basics In-depth understanding of aqs
ReentrantLock usage In
-depth understanding of semaphore Semaphore
In-depth understanding of the three major features
of concurrency In-depth understanding of concurrent programming In-depth understanding of CAS
In-depth understanding of CountDownLatch
Java thread pool
Detailed usage of CyclicBarrier
Detailed usage of CyclicBarrier
Principle of Cyclic Barrier
Example debug to walk through the process
The player t1 t2 thread and the referee main thread are ready for the game.
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;
}
}
}
复制代码
operation result
debug runs the main thread first
no waiting time
specific methodprivate int dowait(boolean timed, long nanos)
You can see that ReentrantLock
the lock , and the count is reduced by one
Block the main thread
Here trip is a conditional queue
private final Condition trip = lock.newCondition();
You can see that a conditional node node is created here
addConditionWaiter method
then LockSupport.park(this); blocks the current thread
You can see that the main thread is already waiting, now let’s go to the t1 thread
Continue to follow the above counting down logic, at this time the count is still not equal to 0
Still will take the wait conditional queue method
Create a new thread node condition node, and enqueue
then continue to park
Next t2 thread await
It will be found that the t2 thread count is 0 at this time, and the nextGeneration(); method is executed
The current t2 thread executes the signalAll method to notify all?
count = parties; reset the counter
Enter the method, get the head node,
Execute the doSignalAll(first) method
to get the head node and set the next pointer to null
transferForSignal method
It is found that the state of the conditional node is set to 0 first, and then a new Node node is createdNode p = enq(node);
New node node
这段代码很熟悉,是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 The counter of CountDownLatch can only be used once, while the counter of CyclicBarrier can be reset using the reset() method. So CyclicBarrier can handle more complex business scenarios, such as if a calculation error occurs, you can reset the counter and let the threads execute it again
- 2 CyclicBarrier also provides getNumberWaiting (you can get the number of threads blocked by CyclicBarrier), isBroken (used to know whether the blocked thread is interrupted) and other methods.
- 3 CountDownLatch will block the main thread, and CyclicBarrier will not block the main thread, but only block the sub-threads.
- 4 Both CountDownLatch and CyclicBarrier can realize the waiting between threads, but they have different emphases. CountDownLatch is generally used for one or more threads, waiting for other threads to complete the task before executing. CyclicBarrier is generally used for a group of threads to wait for each other to a certain state, and then this group of threads executes at the same time.
- 5 CyclicBarrier can also provide a barrierAction to combine multi-thread calculation results.
- 6 CyclicBarrier uses ReentrantLock's "exclusive lock" and Conditon to realize the blocking wakeup of a group of threads, while CountDownLatch is implemented through AQS' "shared lock"