0
点赞
收藏
分享

微信扫一扫

JUC其他常用类

菜菜捞捞 2021-09-30 阅读 36
高并发

CountDownLatch

让一些线程阻塞,知道另一些线程完成一系列操作后才被唤醒。CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,调用线程会被阻塞。其他线程调用countDown方法会将计数器减一,当计数器变为零时,因调用await方法被阻塞的线程会被唤醒,继续执行。

先设定一个场景,公司到了六点,大家都要下班了,大Boss要等到大家都走了,才会锁门

代码

public class CountDownLatchTest {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                // 模拟员工装包
                try {
                    TimeUnit.MILLISECONDS.sleep(new Random(1).nextInt());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t 下班回家");
            }, "employee"+i).start();
        }

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t 锁门");
        }, "boss").start();
    }
}

大家可以多次尝试,会出现类似如下情况

employee2    下班回家
employee6    下班回家
employee5    下班回家
employee7    下班回家
employee0    下班回家
employee3    下班回家
boss     锁门
employee9    下班回家
employee4    下班回家
employee8    下班回家
employee1    下班回家

好家伙,因为有几个员工装包太慢了,黑心老板把几个员工锁在了公司,那这样怎么办呢?
真实情况下,老板知道公司一共有十名员工,可以让老板在门口等着,走一个人就查个数,知道走光了,再锁门

那这个时候就可以请出我们的CountDownLatch类了

public class CountDownLatchTest {
    public static void main(String[] args) {
        // 一共10名员工
        CountDownLatch countDownLatch = new CountDownLatch(10);
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                // 模拟员工装包
                try {
                    TimeUnit.MILLISECONDS.sleep(new Random(3).nextInt());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t 下班回家");
                // 每走一个,就减一
                countDownLatch.countDown();
            }, "employee"+i).start();
        }

        new Thread(() -> {
            // 让老板在门口等着,直到走完才锁门
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "\t 锁门");
        }, "boss").start();
    }
}

CyclicBarrier

CyclicBarrier的字面意思是可循环(cyclic)使用的屏障(barrier)。它要做的事情是,让一组线程到达一个屏障(也叫同步点)时被阻塞,知道最后一个线程到达屏障时,屏障才会打开,所有被屏障拦截的线程才会继续干活,线程进入屏障通过CyclicBarrier的await()方法

其实呢,他跟CountDownLatch相反,CountDownLatch是倒数,CyclicBarrier是正数,还是用一个小情景带大家看一下

情景:现在悟空在收集龙珠,找到一个龙珠没有什么用,必须要集齐七颗才能召唤神龙,那么先找到的龙珠,就让它等一会

public class CyclicBarrierTest {
    public static void main(String[] args) {
        // 构造参数:
        // 1、查几个数,也就是要收集几颗龙珠
        // 2、达到条件后要干嘛
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> System.out.println("召唤神龙"));

        for (int i = 1; i <= 7; i++) {
            new Thread(() -> {
                // 模拟找龙珠的过程
                try {
                    TimeUnit.MILLISECONDS.sleep(new Random(5).nextInt());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "已经找到了");
                // 找到了没有用,所以要等着
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }, i + "星球").start();
        }
    }
}

Semaphore

信号量主要用于两个目的,一个是用于多个共享资源的互斥使用,另一个用于并发线程数的控制。

还是来个情景模拟
类似汽车抢车位,那么车位就是资源,每当有一辆车占用了车位(线程抢占资源),那么信号量就被减一,当没有车位可用时,其他车等待,但是当其他车驶出停车位,那么其他车就又能去抢这个新空出来的车位了

public class SemaphoreTest {
    public static void main(String[] args) {
        // 模拟三个车位
        Semaphore semaphore = new Semaphore(3);

        // 模拟6辆车
        for (int i = 0; i < 6; i++) {
            new Thread(() -> {
                try {
                    // 锁定资源,相当于抢到了一个车位
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "\t抢到车位");

                    TimeUnit.SECONDS.sleep(new Random(3).nextInt());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // 释放资源,相当于车开走
                    semaphore.release();
                    System.out.println(Thread.currentThread().getName() + "\t开走了");
                }
            }, "t"+i).start();
        }
    }
}

输出:

t1  抢到车位
t0  抢到车位
t2  抢到车位
t1  开走了
t0  开走了
t2  开走了
t4  抢到车位
t4  开走了
t3  抢到车位
t5  抢到车位
t3  开走了
t5  开走了

内容均来源于学习资料,在学习过程中进行记录,如有侵权联系作者进行删除

Change the world by program

举报

相关推荐

0 条评论