阅读文本大概需要3分钟。
在Java中CycliBarriar和CountdownLatch有什么区别?CyclicBarrier可以重复使用,而CountdownLatch不能重复使用。
Java的concurrent包里面的CountDownLatch其实可以把它看作一个计数器,只不过这个计数器的操作是原子操作,同时只能有一个线程去操作这个计数器,也就是同时只能有一个线程去减这个计数器里面的值。可以向CountDownLatch对象设置一个初始的数字作为计数值,任何调用这个对象上的await()方法都会阻塞,直到这个计数器的计数值被其他的线程减为0为止。所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。如果需要重置计数,请考虑使用 CyclicBarrier。
CountDownLatch一个非常典型的应用场景:有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如我们这个想要继续往下执行的任务调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDownLatch对象上的countDown()方法,这个调用await()方法的任务将一直阻塞等待,直到这个CountDownLatch对象的计数值减到0为止。
CyclicBarrier一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环的 barrier。
总结如下:
0x01:CountDownLatch类只提供了一个构造器:
-
public CountDownLatch(
int count) {
-
//参数count为计数值
-
}
然后下面这3个方法是CountDownLatch类中最重要的方法:
-
public void await() throws InterruptedException {
-
//调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
-
}
-
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
-
//和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
-
}
-
-
public void countDown() {
-
//将count值减1
-
}
CountDownLatch, 一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
例子代码:
-
import java.util.concurrent.CountDownLatch;
-
-
public class countDownlatchTest {
-
public static void main(String[] args) throws InterruptedException {
-
CountDownLatch countDownLatch =
new CountDownLatch(
5);
-
for(
int i=
0;i<
5;i++){
-
new Thread(
new readNum(i,countDownLatch)).start();
-
}
-
countDownLatch.await();
-
System.out.
println(
"线程执行结束。。。。");
-
}
-
-
static class readNum implements Runnable{
-
private
int id;
-
private CountDownLatch latch;
-
public readNum(
int id,CountDownLatch latch){
-
this.id = id;
-
this.latch = latch;
-
}
-
@Override
-
public void run() {
-
synchronized (this){
-
System.out.
println(
"id:"+id);
-
latch.countDown();
-
System.out.
println(
"线程组任务"+id+
"结束,其他任务继续");
-
}
-
}
-
}
-
}
输出结果:
-
id:
1
-
线程组任务
1结束,其他任务继续
-
id:
0
-
线程组任务
0结束,其他任务继续
-
id:
2
-
线程组任务
2结束,其他任务继续
-
id:
3
-
线程组任务
3结束,其他任务继续
-
id:
4
-
线程组任务
4结束,其他任务继续
-
线程执行结束。。。。
线程在countDown()之后,会继续执行自己的任务,而CyclicBarrier会在所有线程任务结束之后,才会进行后续任务。
0x02: CyclicBarrier用法
CyclicBarrier提供2个构造器
-
public CyclicBarrier(
int parties, Runnable barrierAction) {
-
}
-
-
public CyclicBarrier(
int parties) {
-
}
参数parties指让多少个线程或者任务等待至barrier状态;参数barrierAction为当这些线程都达到barrier状态时会执行的内容。
CyclicBarrier中最重要的方法就是await方法
-
public
int await() throws InterruptedException, BrokenBarrierException {
-
//挂起当前线程,直至所有线程都到达barrier状态再同时执行后续任务;
-
}
-
public
int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException {
-
//让这些线程等待至一定的时间,如果还有线程没有到达barrier状态
-
//就直接让到达barrier的线程执行后续任务
-
举例说明
-
}
例子代码:
-
import java.util.concurrent.CyclicBarrier;
-
-
public class cyclicBarrierTest {
-
public static void main(String[] args) throws InterruptedException {
-
CyclicBarrier cyclicBarrier =
new CyclicBarrier(
5,
new Runnable() {
-
@Override
-
public void run() {
-
System.out.
println(
"线程组执行结束");
-
}
-
});
-
for (
int i =
0; i <
5; i++) {
-
new Thread(
new readNum(i,cyclicBarrier)).start();
-
}
-
//CyclicBarrier 可以重复利用,
-
// 这个是CountDownLatch做不到的
-
// for (int i = 11; i < 16; i++) {
-
// new Thread(new readNum(i,cyclicBarrier)).start();
-
// }
-
}
-
static class readNum implements Runnable{
-
private
int id;
-
private CyclicBarrier cyc;
-
public readNum(
int id,CyclicBarrier cyc){
-
this.id = id;
-
this.cyc = cyc;
-
}
-
@Override
-
public void run() {
-
synchronized (this){
-
System.out.
println(
"id:"+id);
-
try {
-
cyc.await();
-
System.out.
println(
"线程组任务" + id +
"结束,其他任务继续");
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
}
-
}
-
}
-
}
输出结果:
-
id:
1
-
id:
2
-
id:
4
-
id:
0
-
id:
3
-
线程组执行结束
-
线程组任务
3结束,其他任务继续
-
线程组任务
1结束,其他任务继续
-
线程组任务
4结束,其他任务继续
-
线程组任务
0结束,其他任务继续
-
线程组任务
2结束,其他任务继续