使用介绍
有时候多个线程可能需要相互等待对方执行到代码中的某个地方(集合点),这些线程才能够继续执行。
使用流程
使用CyclicBarrier实现等待的线程被称为参与方。参与方值需要执行CyclicBarrier.await()就可以实现等待。尽管从应用代码的的角度来看,参与方是并发执行await()方法的,但是,CyclicBarrier内部维护了一个显式锁,这使得总是可以在所有参与方中区分出一个最后执行await()方法的线程,这被称作最后一个线程。
除最后一个线程外的任何参与方执行await()都会导致该线程被暂停。最后一个线程执行await()会使得使用CyclicBarrier实例的其他所有参与方被唤醒,而最后一个线程自身并不会被暂停。
主线程
public class Main {
static CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
public static void main(String[] args) throws InterruptedException {
for (int number = 1; number <= 5; number++){
ThradDemo thradDemo = new ThradDemo(number, cyclicBarrier);
Thread thread = new Thread(thradDemo);
thread.start();
TimeUnit.SECONDS.sleep(2);
}
}
}
子线程
public class ThradDemo implements Runnable{
CyclicBarrier cyclicBarrier;
int number;
public ThradDemo(int number, CyclicBarrier cyclicBarrier) {
this.number = number;
this.cyclicBarrier = cyclicBarrier;
}
@SneakyThrows
@Override
public void run() {
System.out.println("线程" + number + "准备执行");
cyclicBarrier.await();
System.out.println("线程" + number + "执行完毕");
}
}
执行结果
执行说明
主线程每隔2秒会启动一个子线程执行,子线程打印“准备执行”后,会调用await()方法进行等待,从结果我们可以看出:当最后一个CyclicBarrier.await()方法被执行后,所有的等待线程同时被唤醒,同时开始执行。
CyclicBarrier内部使用了一个条件变量trip来实现等待/通知。CyclicBarrier内部实现使用了分代的概念用于表示CyclicBarrier实例是可以重复使用的。除最后一个线程外的任何一个参与方都相当于一个等待线程,这些线程所使用的保护条件是:“当前分代内,尚未执行await方法的参与方个数为0”。await()方法每被执行一次,相应实例的parties值会减少1.最后一个线程相当于通知线程,它执行await()会使相应实例的parties的值变为0,此线程会先执行barrierAction.run(),然后再执行trip.signalAll()来唤醒所有等待线程。
在测试代码中模拟高并发
在编写多线程程序的测试代码时,我们常常需要使用有线的工作者线程来模拟高并发操作。为此,CyclicBarrier可用来实现这些工作者线程中的任意一个线程在执行其操作前必须等待其他线程也准备就绪,即使得这些工作者线程尽可能在同一时刻开始工作。
方法 | 方法说明 |
---|---|
getParties() | 获取初始化屏障的数量 |
getNumberWaiting() | 获取已经执行await()线程的数量 |
await(long timeout, TimeUnit unit) | 等待一个时间,超过时间后自动唤醒 |
《Java多线程编程实战指南-核心篇》
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。