JUC其他常用类

阅读 36

2021-09-30

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)

0 0 举报