玩碎Java之CountDownLatch / Semaphore / CyclicBarrier

CountDownLatch(倒计数器) - 人去楼空:人都走没了,才能锁门

作用:一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行。

实例:学生放学了,老师等所有学生都离开后,最后离开并锁门(走一个减1,直到走完为0)

(图片来自互联网,如有侵权,请联系删除)

代码

public class CountDownLatchDemo1 {

    private static int COUNT = 8; // 该教室有8个学生

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(COUNT);

        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < COUNT; i++) {
            executorService.submit(new GotoMeat(String.valueOf(i), latch));
        }
        latch.await();
        executorService.shutdown();

        System.out.println("学生都走了,老师可以锁门了!");
    }

    public static class GotoMeat implements Runnable{
        private String name;
        private CountDownLatch latch;

        public GotoMeat(String name, CountDownLatch latch) {
            this.name = name;
            this.latch = latch;
        }


        @Override
        public void run() {
            System.out.println("学生 " + name + " 已经离开... ");
            latch.countDown();
        }
    }
}

Semaphore(信号量,限流) - 食堂打饭:只有3个窗口可以同时打饭

作用:Semaphore用于限制可以访问某些资源(物理或逻辑的)的线程数目,他维护了一个许可证集合,有多少资源需要限制就维护多少许可证集合,假如这里有N个资源,那就对应于N个许可证,同一时刻也只能有N个线程访问。一个线程获取许可证就调用acquire方法,用完了释放资源就调用release方法。

实例:高速路收费站有5个收费口,不管后面有多少辆车,每次只能通行5辆

(图片来自网络)

代码

public class SemaphoreDemo1 {

    private static int COUNT = 5; // 共有5辆车等待通过收费口
    private static int LIMIT = 2; // 有2个收费口

    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(LIMIT);

        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < COUNT; i++) {
            executorService.submit(new PassThroughTheToll(String.valueOf(i), semaphore));
        }
        executorService.shutdown();
    }

    public static class PassThroughTheToll implements Runnable {

        private String name;
        private Semaphore semaphore;

        public PassThroughTheToll(String name, Semaphore semaphore) {
            this.name = name;
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            try {
                semaphore.acquire();
                System.out.println("车辆 " + name + "拿到了通过收费站的许可...");
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("车辆 " + name + "通过收费站,释放了许可~~~");
                semaphore.release();
            }
        }
    }
}

CyclicBarrier(屏障) - 运动员互相等待就位:全就位后,裁判发枪

作用:CyclicBarrier允许一组线程在到达某个栅栏点(common barrier point)互相等待,直到最后一个线程到达栅栏点,栅栏才会打开,处于阻塞状态的线程恢复继续执行。

实例:师徒四人,都准备好了(到达公共屏障点common barrier point,相当于一个障碍点),再一起走(在障碍点一个都不能少,到齐后才能一起干大事)

实例2:田径比赛,各位运动员都准备好就位之后,裁判发枪

查看源图像

(图片来源互联网)

代码

public class CyclicBarrierDemo1 {

    private static int COUNT = 4; // 师徒四人

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(COUNT);
        String[] names = {"唐老板", "猴哥", "八戒", "沙和尚"};

        ExecutorService executorService = Executors.newFixedThreadPool(COUNT);
        for (int i = 0; i < COUNT; i++) {
            executorService.submit(new Travel(names[i], cyclicBarrier));
        }
        executorService.shutdown();
    }

    static class Travel implements Runnable {

        private String name;
        private CyclicBarrier cyclicBarrier;

        public Travel(String name, CyclicBarrier cyclicBarrier) {
            this.name = name;
            this.cyclicBarrier = cyclicBarrier;
        }

        @Override
        public void run() {
            try {
                TimeUnit.SECONDS.sleep(1+(new Random().nextInt(3)));
                System.out.println(name + "已就位...,等待其他成员到来");
                cyclicBarrier.await();
                System.out.println(name + " :看到所有成员已到齐,四人一起过流沙河");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}

CountDownLatch 与 CyclicBarrier 的区别

CountDownLatchCyclicBarrier
减计数方式加计数方式
计数为0时,释放所等有待的线程计数达到指定值时,释放所有等待的线程
计数为0时,无法重置计数达到指定值时,计数置为0,重新开始

调用countDown()方法减1

调用await()方法只进行阻塞,对计数没任何影响

await()方法计数加1,

若加1后的值不等于初始指定的值,则线程阻塞

不可重复利用可重复利用

CountDownLatch是计数器,线程完成一个记录一个,只不过计数不是递增而是递减;

CyclicBarrier更像是一个阀门,需要所有线程都要到达,阀门才能打开,然后继续执行。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值