并发工具类CountDownLatch、CyclicBarrier和Semaphore

在JDK的并发包中提供了几个常用的并发工具类:CountDownLatch、CyclicBarrier和Semaphore。这三个是 JUC 中较为常用的同步器,通过它们可以方便地实现很多线程之间协作的功能。

一、CountDownLatch

CountDownLatch允许一个或多个线程等待其他线程完成操作。它通过一个计数器来实现,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后等待的线程就可以恢复执行任务。

现在有一个旅行团,有五个人要去旅游,大巴需要5个人同时坐上车才可以出发。

public class CountDownLatchDemo {
    /**
     * 需要5个人坐车
     */
    private static final CountDownLatch COUNT = new CountDownLatch(5);

    public static void main(String[] args) {
        for (int i = 1; i <= 5; i++) {
            final int ii = i;
            new Thread(() -> {
                int time = new Random().nextInt(1000);
                System.out.println("乘客" + ii + "准备时间:" + time / 1000.0 + "s");
                try {
                    //模拟准备就绪的时间
                    Thread.sleep(time);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("乘客" + ii + "准备就绪");
                COUNT.countDown();
                System.out.println("乘客" + ii + "上车");
            }).start();
        }
        try {
            //有乘客未上车,无法出发
            COUNT.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("------------出发------------");
    }
}

代码运行结果:

乘客2准备时间:0.252s
乘客5准备时间:0.337s
乘客4准备时间:0.36s
乘客3准备时间:0.905s
乘客1准备时间:0.115s
乘客1准备就绪
乘客1上车
乘客2准备就绪
乘客2上车
乘客5准备就绪
乘客5上车
乘客4准备就绪
乘客4上车
乘客3准备就绪
乘客3上车
------------出发------------

可以看到,不管乘客准备时间多久,大巴(主线程)都会等所有乘客就绪之后才会出发,否则不能出发(阻塞)。

二、CyclicBarrier

CyclicBarrier的字面意思是可循环利用(Cyclic)的屏障(Barrier),让一组线程到达一个屏障(或同步点)时被阻塞,直到最后一个线程到达屏障,屏障才会开门,所有被屏障拦截的线程才会继续运行。

现在旅行团的所有成员都到了目的地点,为了保证安全,导游需要五个人同时准备好后才可以进入旅游景点。​​​​​​​

public class CyclicBarrierDemo {
    /**
     * 5个人进旅游景点
     */
    private static final CyclicBarrier BARRIER = new CyclicBarrier(5);

    public static void main(String[] args) {
        for (int i = 1; i <= 5; i++) {
            final int ii = i;
            new Thread(() -> {
                int time = new Random().nextInt(1000);
                System.out.println("乘客" + ii + "准备时间:" + time / 1000.0 + "s");
                try {
                    //模拟准备就绪的时间
                    Thread.sleep(time);
                    System.out.println("乘客" + ii + "准备就绪");
                    BARRIER.await();
                    System.out.println("乘客" + ii + "进入旅游景点");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

程序运行结果:

乘客4准备时间:0.904s
乘客5准备时间:0.634s
乘客1准备时间:0.964s
乘客2准备时间:0.324s
乘客3准备时间:0.731s
乘客2准备就绪
乘客5准备就绪
乘客3准备就绪
乘客4准备就绪
乘客1准备就绪
乘客1进入旅游景点
乘客5进入旅游景点
乘客2进入旅游景点
乘客4进入旅游景点
乘客3进入旅游景点

我们看到只有所有的人(5个线程)都准备就绪时,乘客才能一起进入旅游景点(barrier放行)。

三、Semaphore

Semaphore是用来控制同时访问特定资源的线程数量,他通过协调各个线程,以保证合理的使用公共资源。

旅游团的成员都到达了旅游景点之后,大巴司机就去停车场停车。​​​​​​​

public class SemaphoreDemo {

    /**
     * 停车场一共有三个车位
     */
    private static final Semaphore SEMAPHORE = new Semaphore(3);

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            final int ii = i;
            new Thread(() -> {
                try {
                    int time = new Random().nextInt(1000) + 2000;
                    SEMAPHORE.acquire();
                    System.out.println("车" + ii + "抢到车位,停车:" + time / 1000.0 + "s,剩余车位" + SEMAPHORE.availablePermits());
                    Thread.sleep(time);
                    SEMAPHORE.release();
                    System.out.println("车" + ii + "开走啦,剩余车位" + SEMAPHORE.availablePermits());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

运行结果:

车7抢到车位,停车:2.735s,剩余车位0
车6抢到车位,停车:2.141s,剩余车位0
车1抢到车位,停车:2.688s,剩余车位0
车6开走啦,剩余车位1
车4抢到车位,停车:2.047s,剩余车位0
车1开走啦,剩余车位1
车3抢到车位,停车:2.408s,剩余车位0
车7开走啦,剩余车位1
车2抢到车位,停车:2.04s,剩余车位0
车4开走啦,剩余车位1
车8抢到车位,停车:2.779s,剩余车位0
车2开走啦,剩余车位1
车5抢到车位,停车:2.729s,剩余车位0
车3开走啦,剩余车位1
车0抢到车位,停车:2.503s,剩余车位0
车8开走啦,剩余车位1
车9抢到车位,停车:2.049s,剩余车位0
车5开走啦,剩余车位1
车0开走啦,剩余车位2
车9开走啦,剩余车位3

可以看到,只有前边有车开走(线程释放),才能继续有车进入抢到车位停车。

四、总结

其实CountDownLatch和CyclicBarrier很相似,都是达到一个数量才能执行操作,但CountDownLatch关注的是其他线程的调用者(本例子指的是主线程main),而CyclicBarrier关注的是其他线程本身,阻塞的线程不同。并且CountDownLatch计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()进行重置操作,重新开始计数。

Semaphore比较好理解,起到一个流控的作用。Semaphore的构造方法传入一个整数,表示permit许可证的意思,只有拿到许可证才能进行接下来的操作,用完之后归还许可证即可。

今天的分享就到此结束啦,喜欢的小伙伴记得点赞呦。

关注公众号JavaGrowUp,下期不迷路,获取更多精彩内容。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值