CountDownLatch : 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行。
CyclicBarrier : N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。
这样应该就清楚一点了,对于CountDownLatch来说,重点是那个“一个线程”, 是它在等待, 而另外那N的线程在把“某个事情”做完之后可以继续等待,可以终止。而对于CyclicBarrier来说,重点是那N个线程,他们之间任何一个没有完成,所有的线程都必须等待。
CountDownLatch 是计数器, 线程完成一个就记一个, 就像 报数一样, 只不过是递减的.
而CyclicBarrier更像一个水闸, 线程执行就想水流, 在水闸处都会堵住, 等到水满(线程到齐)了, 才开始泄流.
CountDownLatch | CyclicBarrier |
减计数方式 | 加计数方式 |
计算为0时释放所有等待的线程 | 计数达到指定值时释放所有等待线程 |
计数为0时,无法重置 | 计数达到指定值时,计数置为0重新开始 |
调用countDown()方法计数减一,调用await()方法只进行阻塞,对计数没任何影响 | 调用await()方法计数加1,若加1后的值不等于构造方法的值,则线程阻塞 |
不可重复利用 | 可重复利用 |
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的简单demo:
package Thread;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchTest {
public static void main(String[] args) {
//5为计数值
CountDownLatch countDownLatch = new CountDownLatch(5);
for (int i = 1; i < 6; i++) {
new Thread(new readNum(i, countDownLatch)).start();
}
try {
//调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
//此时是主线程被挂起,等5个子线程执行完成后主线程接着执行
countDownLatch.await();
//让主线程睡1000ms让结果更明显
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
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);
//调用countDown()方法,将countDownLatch值减1
latch.countDown();
System.out.println("线程组任务" + id + "结束,其他任务继续");
try {
//线程睡100ms,让结果更明显
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
执行结果如下:
id:2
线程组任务2结束,其他任务继续
id:3
线程组任务3结束,其他任务继续
id:5
id:4
线程组任务4结束,其他任务继续
id:1
线程组任务5结束,其他任务继续
线程组任务1结束,其他任务继续
线程执行结束。。。。
可以看出来,只有主线程调用了await()方法并且阻塞,即就是只有主线程等待其他的5个子线程执行完成,主线程在接着向下执行
一个关于CyclicBarrier的简单demo:
package Thread;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierTest2 {
public static void main(String[] args) {
//定义6个线程需要等待
CyclicBarrier cyclicBarrier = new CyclicBarrier(6);
for (int i = 0; i < 5; i++) {
new Thread(new readNum(i, cyclicBarrier)).start();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
//主线程睡1000ms,等子线程全部执行完成后,主线程在调用await()方法,
//将count值加1,此时cyclicBarrier的count值已经等于6,全部的线程开始接着向下执行
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//主线程在睡1000ms,等5个子线程都打印完成,在接着向下执行
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("主线程执行结束。。。。");
}
static class readNum implements Runnable {
private int id;
private CyclicBarrier barrier;
public readNum(int id, CyclicBarrier barrier) {
this.id = id;
this.barrier = barrier;
}
@Override
public void run() {
{
System.out.println("id:" + id);
try {
//每一个线程进来调用await()方法,将barrier的count值加1
barrier.await();
System.out.println("线程组任务" + id + "结束,其他任务继续");
}
catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
运行结果如下所示:
id:1
id:2
id:0
id:3
id:4
线程组任务1结束,其他任务继续
线程组任务0结束,其他任务继续
线程组任务4结束,其他任务继续
线程组任务2结束,其他任务继续
线程组任务3结束,其他任务继续
主线程执行结束。。。。
可以看出来,主线程和每个子线程都调用了await()方法,他们之间是相互等待的。