spingboot

CountDownLatch、CyclicBarrier以及Se

2019-07-24  本文已影响14人  bearPotMan

CountDownLatch
简单讲就是可以实现 “倒计时” 的一个工具类,提供了两个基本的方法,倒计数方法 countDown() 和 阻塞等待方法 await()。下面通过一个简单的案例来看一下具体该如何使用。
看过香港警匪片的朋友应该很熟悉这样一个场景:假设本次行动警察要抓获 6 个犯罪分子,但是除了第一个犯罪分子,其余犯罪分子的位置都是未知的,得抓一个问一个才能知道,要抓幕后大老板,得把前第5 个犯罪分子抓捕归案才能知道老板的位置,抓了老板才算结案!虽然有点扯,但有助于理解 CountDownLatch 的使用!看代码

public class CountDownLatchDemo {
    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(6);
        for (int i = 0; i < 6; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + " 号嫌疑人被抓");
                countDownLatch.countDown();
            }, String.valueOf(i)).start();
        }
        try {
            countDownLatch.await();
            System.out.println("所有嫌疑人被抓捕,结案!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

看结果:

1 号嫌疑人被抓
0 号嫌疑人被抓
4 号嫌疑人被抓
2 号嫌疑人被抓
3 号嫌疑人被抓
5 号嫌疑人被抓
所有嫌疑人被抓捕,结案!

CyclicBarrier
与 CountDownLatch 的作用恰好相反。
来个案例强行解释一波。
想必看过复联3的朋友都知道灭霸吧,灭霸要完成自己的宏图大业,必须要集齐六颗宝石,那么我们就来看一下灭霸是如何集齐六颗宝石,打完响指并毁灭半数人类的。

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(6, () -> System.out.println("灭霸响指,毁灭性的时刻"));
        for (int i = 1; i <= 6; i++) {
            final int temp = i;
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + " 收集到了 " + GemEnum.forEach(temp).getDesc());
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }, String.valueOf(i)).start();
        }
    }
}

enum GemEnum {
    SPACE_GEM(1, "空间宝石"),
    POWER_GEM(2, "力量宝石"),
    TIME_GEM(3, "时间宝石"),
    MIND_GEM(4, "心灵宝石"),
    SOUL_GEM(5, "灵魂宝石"),
    REALISTIC_GEM(6, "现实宝石");

    private Integer number;
    private String desc;

    GemEnum(Integer number, String desc) {
        this.number = number;
        this.desc = desc;
    }

    public Integer getNumber() {
        return number;
    }

    public String getDesc() {
        return desc;
    }

    public static GemEnum forEach(int index) {
        GemEnum[] gemEnums = GemEnum.values();
        for (GemEnum gemEnum : gemEnums) {
            if (index == gemEnum.getNumber()) {
                return gemEnum;
            }
        }
        return null;
    }
}

看下面的结果,完美!

1 收集到了 空间宝石
5 收集到了 灵魂宝石
4 收集到了 心灵宝石
2 收集到了 力量宝石
3 收集到了 时间宝石
6 收集到了 现实宝石
灭霸响指,毁灭性的时刻

Semaphore
信号量通常用于控制线程数!
看这么一个案例:车站只有 3 个售票窗口,每个窗口只能单次服务一位顾客,现在假设有 5 位顾客前来购票,前三位每人一个窗口办理手续,后两位就必须等着前三位办完手续,等窗口空闲了再去办理。看代码

public class SemaphoreDemo {
    public static void main(String[] args) {
        // 3 个窗口
        Semaphore semaphore = new Semaphore(3);
        // 5位顾客
        for (int i = 1; i <= 5; i++) {
            new Thread(() -> {
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + " 号顾客买票");
                    try {
                        // 假设每位顾客买票耗时 3 秒
                        TimeUnit.SECONDS.sleep(3);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " 号顾客买完票离开");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release();
                }
            }, String.valueOf(i)).start();
        }
    }
}

看结果:

3 号顾客买票
1 号顾客买票
2 号顾客买票
2 号顾客买完票离开
1 号顾客买完票离开
3 号顾客买完票离开
4 号顾客买票
5 号顾客买票
5 号顾客买完票离开
4 号顾客买完票离开

以上就是它们三个的简单使用,了解的知识点多了之后,对于不同的场景,你就会有不同的解决方案!加油...

上一篇 下一篇

猜你喜欢

热点阅读