天天看点

CountDownLatch和CyclicBarrier的爱恨情仇CountDownLatch和CyclicBarrier的简介CountDownLatch的代码举例:CyclicBarrier的代码举例:

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号运动员跑了出去

继续阅读