本文已参与「新人创作礼」活动,一起开启掘金创作之路。
简介
可重复使用的线程控制器、适用于多个线程需到达某个状态之后再同时开始执行的场景,就好似有道屏障,只有在屏障处等待的线程到指定数量这个屏障才会打开。
常用方法
- CyclicBarrier(int parties, Runnable barrierAction):构造方法,parties标识要控制的线程数,即当多少个线程在屏障处等待时就放行。barrierAction为需要在放行时同步执行的操作。
- CyclicBarrier(int parties):构造方法,parties标识要控制的线程数,即当多少个线程在屏障处等待时就放行。
- int getParties():获得要控制的线程数,即当多少个线程在屏障处等待时就放行。
- int await():等待屏障处线程达到数量
- int await(long timeout, TimeUnit unit):等待屏障处线程达到数量 带超时时间
- boolean isBroken():屏障是否已经被破坏 true为已被破坏
- void reset():CyclicBarrier可重复使用并不代表屏障每开启一次就要调这个方法一次。每当屏障处到达指定数量的等待线程,屏障会开启并自动关闭等待下一波线程。无需每开启一次就重置一次。这个方法使屏障恢复初始状态,不过如果在重置时有线程在屏障处等待,则抛出BrokenBarrierException.
- int getNumberWaiting():获得当前在屏障处等待的线程数
示例
package sync;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class CyclicBarrierTest {
public static void main(String[] args) {
Runnable allAwaitRun = new Runnable() {
@Override
public void run() {
System.out.println("大家都执行完毕了,准备下一步工作喽");
}
};
final CyclicBarrier c = new CyclicBarrier(3, allAwaitRun); // 参数二为屏障放行之后要启的线程
// 如果你实际有3个线程但是屏障设置为2,那么先到的2个会被屏障放行,
//最后一个屏障并不知道也不去管,导致最后一个到的一直等待或者超时报TimeoutException
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("线程1开始进行第一步工作...");
try {
Thread.sleep(500); // 等待模式耗时操作
System.out.println("线程1第一步工作完毕,进入等待状态...当前等待线程量 - " + c.getNumberWaiting());
try {
System.out.println("r1.await - " + c.await(2, TimeUnit.SECONDS)); // await返回该线程到达屏障的顺序,最快的为n-1,最慢的为0
} catch (BrokenBarrierException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
System.out.println("线程1通过屏障");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Runnable r2 = new Runnable() {
@Override
public void run() {
System.out.println("线程2开始进行第一步工作...");
try {
Thread.sleep(1000);// 等待模式耗时操作
System.out.println("c2 - " + c.isBroken());
System.out.println("线程2第一步工作完毕,进入等待状态...当前等待线程量 - " + c.getNumberWaiting());
try {
System.out.println("r2.await - " + c.await(2, TimeUnit.SECONDS));
} catch (BrokenBarrierException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
System.out.println("线程2通过屏障");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Runnable r3 = new Runnable() {
@Override
public void run() {
System.out.println("线程3开始进行第一步工作...");
try {
Thread.sleep(1500);// 等待模式耗时操作
// Thread.sleep(5000);// 等待模式耗时操作 5s的话显而易见的会报超时,由先到屏障处即await返回值为n-1的那个线程抛出TimeoutException
//超时异常一经抛出,屏障被破坏,因此会导致其他已在屏障处的等待线程await抛出 BrokenBarrierException.
// (依据对这个异常的处理(catch还是throws(Callable可抛出异常))来判定线程是继续执行还是抛出停止)
//但是对线程3因为此线程延迟5s,所以此时还没到屏障处
// 所以会继续执行,直至到达屏障处发现屏障已被破坏,抛出BrokenBarrierException
System.out.println("线程3第一步工作完毕,进入等待状态...当前等待线程量 - " + c.getNumberWaiting());
try {
System.out.println("r3.await - " + c.await(2, TimeUnit.SECONDS));
} catch (BrokenBarrierException e) {
System.out.println("e - " + c.isBroken()); // 设置sleep(5000)时屏障被击穿 这里为true
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
System.out.println("线程3通过屏障");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
new Thread(r1).start();
new Thread(r2).start();
new Thread(r3).start();
System.out.println("c.getParties() - " + c.getParties()); // CyclicBarrier掌控的线程数
c.reset(); // 重置,如果此时有线程在屏障处等待,那么抛出BrokenBarrierException
}
}
运行结果:
线程1开始进行第一步工作...
线程3开始进行第一步工作...
c.getParties() - 3
线程2开始进行第一步工作...
线程1第一步工作完毕,进入等待状态...当前等待线程量 - 0
c2 - false
线程2第一步工作完毕,进入等待状态...当前等待线程量 - 1
线程3第一步工作完毕,进入等待状态...当前等待线程量 - 2
大家都执行完毕了,准备下一步工作喽
r3.await - 0
线程3通过屏障
r1.await - 2
线程1通过屏障
r2.await - 1
线程2通过屏障
PS:
开发成长之旅 [持续更新中...]
关联导航:20:线程控制器CountDownLatch - 掘金 (juejin.cn)
关联导航:22:线程控制器Semaphore - 掘金 (juejin.cn)
欢迎关注...