文章目录
- 前言
- 一、CyclicBarrier可以做什么?
- 二、使用步骤
- 1 单参数CyclicBarrier
- 2 多参数 CyclicBarrier
- 3 与CyclicBarrier类似的Exchanger
- 总结
前言
多线程中的CyclicBarrier,同样也是juc包下的一个工具类;
一、CyclicBarrier可以做什么?
CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞;
意思就是:
- 当我创建CyclicBarrier 的时候,入参就是屏障拦截线程的个数;
- 当没有达到这个屏障拦截个数的时候,那么所有线程均被阻塞
- 每个线程调用 CyclicBarrier 的 await(); 算是告诉 CyclicBarrier 到达了屏障
二、使用步骤
1 单参数CyclicBarrier
例如如下代码:
public class CyclicBarrierTest{
/**
* int 入参 其参数表示屏障拦截的线程数量,
* 每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞
* 只有线程的阻塞数量(到达屏障的数量) 与int 入参相当的时候,线程才会进入就绪状态,开始执行
*/
static CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
@SneakyThrows
public static void main(String[] args) {
new Thread(() -> {
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (BrokenBarrierException e) {
throw new RuntimeException(e);
}
System.out.println("我是子线程");
}).start();
cyclicBarrier.await();
System.out.println("我是主线程");
}
}
- 其中创建CyclicBarrier 的时候入参为2
- 那么只有当有2 个线程调用了 CyclicBarrier 的 await()方法的时候,才会真正执行,否则一直被阻塞;
- 当 static CyclicBarrier cyclicBarrier = new CyclicBarrier(3); 那么执行这个方法,会一直阻塞,因为没有第三个线程调用 await() 方法;
当改为3 之后
说明两个线程均被阻塞,正在等待第三个线程到达屏障,才会继续执行;
2 多参数 CyclicBarrier
例如如下代码:
public class CyclicBarrierPriority {
static CyclicBarrier cyclicBarrier = new CyclicBarrier(2,() -> System.out.println("我先执行"));
@SneakyThrows
public static void main(String[] args) {
new Thread(() -> {
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (BrokenBarrierException e) {
throw new RuntimeException(e);
}
System.out.println("1");
}).start();
cyclicBarrier.await();
System.out.println("2");
}
}
- 第一个参数 与第一种相同,都是等待达到屏障的线程目标数量
- 第二个参数是 一个线程,它是一个最优先执行的线程; 当符合屏障数量之后,先执行第二个参数 也就是这个线程;
当入参中的第一个参数改为 3
那么这个线程永远不会执行,与之前类似,因为不会有第三个线程达到屏障,所以一直阻塞所有线程;
3 与CyclicBarrier类似的Exchanger
感觉应用场景不多,所以不单独写一片了,就在此处补充下; Exchanger与线程屏障功能类似,不通的是,它不是通过计数的形式,而是通过是否得到交换信息而实现的;
代码如下:
public class 线程交换信息 {
@SneakyThrows
public static void main(String[] args) {
Exchanger<String> stringExchanger = new Exchanger<>();
Thread thread = new Thread(() -> {
System.out.println(Thread.currentThread().getName());
try {
System.out.println(Thread.currentThread().getName() + "我接受到了消息: " + stringExchanger.exchange("你好"));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
thread.setName("第一个");
thread.start();
Thread.sleep(2000);
Thread thread1 = new Thread(() -> {
System.out.println(Thread.currentThread().getName());
try {
System.out.println(Thread.currentThread().getName() + "我接受到了消息: " + stringExchanger.exchange("hello"));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
thread1.setName("第二个");
thread1.start();
}
}
当第二个线程不运行的时候,第一个线程就会一直阻塞
直到有第二个线程与它进行信息交换后,两个线程才会继续运行
如果两个线程有一个没有执行exchange()方法,则会一直等待,如果担心有特殊情况发生,避免一直等待,可以使用exchange(V x,longtimeout,TimeUnit unit)设置最大等待时长;
总结
CyclicBarrier可以用于多线程计算数据,最后合并计算结果的场景; 与这篇文章类似:
多线程处理有序集合