CountDownLatch和CyclicBarrier的简介
CountDownLatch:
闭锁/线程递减锁。对线程进行计数,在计数归零之前线程会陷入阻塞;直到计数归零为止,才会放开阻塞。简而言之:一组线程结束之后开启另一组线程。
俗例:六个人约饭,其中五个人先到了饭馆,和老板说了- -句话:"老板,我们人还没齐,等人齐了再上菜" -闭锁。
CyclicBarrier:
栅栏。对线程进行计数,在计数归零之前线程会陷入阻塞;直到计数归零为止,才会放开阻塞。简而言之:这一组线程到达同一个点之后再分别继续执行 。
俗例:超市早晨开门之前,一群大爷大妈围在超市门口,超市开门之后,这群大爷大妈蜂拥而入开始抢购-栅栏。
CountDownLatch和CyclicBarrier区别和联系:
CountDownLatch | CyclicBarrier |
创建:CountDownLatch cdl = new CountDownLatch(7) | 创建:CyclicBarrier cb = new CyclicBarrier(6) |
做减法计数
| 做加法计数 |
所有的线程到达之后再去执行“另外一个线程” | 所有的线程到达之后再去执行“各自的线程” |
CountDownLatch的代码举例:
/*
举例:考试
考官到考场
考生到考场
考试开始
*/
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch cdl = new CountDownLatch(7);
new Thread(new Teacher(cdl)).start();
new Thread(new Teacher(cdl)).start();
new Thread(new Student(cdl)).start();
new Thread(new Student(cdl)).start();
new Thread(new Student(cdl)).start();
new Thread(new Student(cdl)).start();
new Thread(new Student(cdl)).start();
// 正常情况下:应该是考官和考生都到达考场之后才能开始考试
// 在上面七个线程执行完成之前,主线程应该陷入阻塞
// 在计数归零之前,需要阻塞
cdl.await();
System.out.println("开始考试");
}
}
class Teacher implements Runnable {
private CountDownLatch cdl;
public Teacher(CountDownLatch cdl) {
this.cdl = cdl;
}
@Override
public void run() {
try {
// 模拟考官到考场的时间
Thread.sleep((long) (Math.random() * 10000));
System.out.println("考官到达考场");
// 减少一个计数
cdl.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Student implements Runnable {
private CountDownLatch cdl;
public Student(CountDownLatch cdl) {
this.cdl = cdl;
}
@Override
public void run() {
try {
// 模拟考生到达考场的时间
Thread.sleep((long) (Math.random() * 10000));
System.out.println("考生到达考场");
cdl.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
执行结果:在所有的考官和考生到达考场之后才会去进行考试。
考官到达考场
考生到达考场
考生到达考场
考生到达考场
考官到达考场
考生到达考场
考生到达考场
开始考试
CyclicBarrier的代码举例:
/*
举例:跑步比赛
所有的运动员都到了起跑线之后,才能往外跑
*/
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cb = new CyclicBarrier(6);
new Thread(new Runner(cb), "1号").start();
new Thread(new Runner(cb), "2号").start();
new Thread(new Runner(cb), "3号").start();
new Thread(new Runner(cb), "4号").start();
new Thread(new Runner(cb), "5号").start();
new Thread(new Runner(cb), "6号").start();
}
}
// 运动员
class Runner implements Runnable {
private CyclicBarrier cb;
public Runner(CyclicBarrier cb) {
this.cb = cb;
}
@Override
public void run() {
try {
// 模拟每一个人到起跑线的时间
Thread.sleep((long) (Math.random() * 10000));
String name = Thread.currentThread().getName();
System.out.println(name + "运动员到了起跑线");
// 正常情况下:应该是所有的运动员都到了起跑线之后才能往外跑
// 也就意味着先到的运动员应该在这儿等待,等大家到齐再往外跑
// 在阻塞的时候同时减少计数,当计数归零之后放开阻塞
cb.await();
System.out.println(name + "运动员跑了出去");
} catch (Exception e) {
e.printStackTrace();
}
}
}
执行结果:在所有的运动员到达起跑线之后,然后所有的运动员才开始各自起跑。
5号运动员到了起跑线
6号运动员到了起跑线
2号运动员到了起跑线
4号运动员到了起跑线
3号运动员到了起跑线
1号运动员到了起跑线
1号运动员跑了出去
5号运动员跑了出去
2号运动员跑了出去
3号运动员跑了出去
4号运动员跑了出去
6号运动员跑了出去