【小家java】JUC并发编程工具之CountDownLatch(闭锁)、CyclicBarrier、Semaphore的使用(下)

简介: 【小家java】JUC并发编程工具之CountDownLatch(闭锁)、CyclicBarrier、Semaphore的使用(下)

CyclicBarrier和CountDownLatch的区别


   CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。


   CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。比如以下代码执行完之后会返回true。


   CountDownLatch是减计数方式,而CyclicBarrier是加计数方式


   CountDownLatch不可以复用,而CyclicBarrier可以复用。


Semaphore


Semaphore是一种计数信号量,用于管理一组资源,内部是基于AQS的共享模式。它相当于给线程规定一个量从而控制允许活动的线程数。


Semaphore是一种在多线程环境下使用的设施,该设施负责协调各个线程,以保证它们能够正确、合理的使用公共资源的设施,也是操作系统中用于控制进程同步互斥的量。

原来阐述


以一个停车场为例。加入一共只有3个停车位,那么当来了5辆车的时候,那么看门的人可以不受阻碍的放3辆车进去,其余的在入口处等候。这时候如果继续来车就都得在门外等候。


这时,如果有一辆车停车位里的车离开了,就可以放一辆进来了(至于放哪俩进来,有公平锁和非公平锁之分),如此往复。


每辆车就好比一个线程,看门人就好比一个信号量,看门人限制了可以活动的线程。

对于Semaphore类而言,就如同一个看门人,限制了可活动的线程数。


主要方法:

Semaphore(int permits):构造方法,创建具有给定许可数的计数信号量并设置为非公平信号量。
Semaphore(int permits,boolean fair):构造方法,当fair等于true时,创建具有给定许可数的计数信号量并设置为公平信号量。
void acquire():从此信号量获取一个许可前线程将一直阻塞。相当于一辆车占了一个车位。
void acquire(int n):从此信号量获取给定数目许可,在提供这些许可前一直将线程阻塞。比如n=2,就相当于一辆车占了两个车位。
void release():释放一个许可,将其返回给信号量。就如同车开走返回一个车位。
void release(int n):释放n个许可。
int availablePermits():当前可用的许可数。


代码示例


就以上面的提车系统,用代码里实现(仅供参考)


    //控制三个停车位
    private static final Semaphore semaphore = new Semaphore(3);
    //线程池:核心线程数可以有5个
    private static final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
            5, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
    //一辆车代表一个进程 进去提车系统
    private static class CarThread extends Thread {
        private final String name; //品牌名称
        private final int age; //使用了多少年
        public CarThread(String name, int age) {
            this.name = name;
            this.age = age;
        }
        @Override
        public void run() {
            try {
                semaphore.acquire(); //常识去获取许可 进入停车
                System.out.println(Thread.currentThread().getName() + ":大家好,我是【" + name + "】使用了【" + age + "】年,当前时间为:" + System.currentTimeMillis());
                Thread.sleep(1000); //模拟停车时长 停后离开
                System.out.println("【" + name + "】要准备离开停车场了,当前剩余空位【" + semaphore.availablePermits() + "】,当前时间为:" + System.currentTimeMillis());
                semaphore.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        String[] name = {"奔驰", "宝马", "奥迪", "大众", "尼桑", "wey派", "领克"};
        int[] age = {1, 3, 5, 6, 7, 10, 12};
        //一次性来了7辆车
        for (int i = 0; i < 7; i++) {
            threadPool.execute(new CarThread(name[i], age[i]));
        }
    }
输出:
pool-1-thread-3:大家好,我是【奥迪】使用了【5】年,当前时间为:1544953335062
pool-1-thread-2:大家好,我是【宝马】使用了【3】年,当前时间为:1544953335062
pool-1-thread-1:大家好,我是【奔驰】使用了【1】年,当前时间为:1544953335063
【奔驰】要准备离开停车场了,当前剩余空位【0】,当前时间为:1544953336081
pool-1-thread-1:大家好,我是【wey派】使用了【10】年,当前时间为:1544953336081
【奥迪】要准备离开停车场了,当前剩余空位【0】,当前时间为:1544953336085
pool-1-thread-4:大家好,我是【大众】使用了【6】年,当前时间为:1544953336088
【宝马】要准备离开停车场了,当前剩余空位【0】,当前时间为:1544953336088
pool-1-thread-5:大家好,我是【尼桑】使用了【7】年,当前时间为:1544953336089
【wey派】要准备离开停车场了,当前剩余空位【0】,当前时间为:1544953337083
pool-1-thread-3:大家好,我是【领克】使用了【12】年,当前时间为:1544953337083
【大众】要准备离开停车场了,当前剩余空位【0】,当前时间为:1544953337089
【尼桑】要准备离开停车场了,当前剩余空位【1】,当前时间为:1544953337094
【领克】要准备离开停车场了,当前剩余空位【2】,当前时间为:1544953338083
private static final Semaphore semaphore = new Semaphore(3, true);


运行:


输出:
pool-1-thread-2:大家好,我是【宝马】使用了【3】年,当前时间为:1544953560457
pool-1-thread-3:大家好,我是【奥迪】使用了【5】年,当前时间为:1544953560457
pool-1-thread-1:大家好,我是【奔驰】使用了【1】年,当前时间为:1544953560457
【奔驰】要准备离开停车场了,当前剩余空位【0】,当前时间为:1544953561468
pool-1-thread-4:大家好,我是【大众】使用了【6】年,当前时间为:1544953561468
【奥迪】要准备离开停车场了,当前剩余空位【0】,当前时间为:1544953561468
pool-1-thread-5:大家好,我是【尼桑】使用了【7】年,当前时间为:1544953561468
【宝马】要准备离开停车场了,当前剩余空位【0】,当前时间为:1544953561469
pool-1-thread-1:大家好,我是【wey派】使用了【10】年,当前时间为:1544953561469
【大众】要准备离开停车场了,当前剩余空位【0】,当前时间为:1544953562468
pool-1-thread-3:大家好,我是【领克】使用了【12】年,当前时间为:1544953562468
【尼桑】要准备离开停车场了,当前剩余空位【0】,当前时间为:1544953562469
【wey派】要准备离开停车场了,当前剩余空位【0】,当前时间为:1544953562469
【领克】要准备离开停车场了,当前剩余空位【2】,当前时间为:1544953563470


从输出的结果可以看出"大众", “尼桑”, “wey派”, "领克"是排队按照顺序进入的,这时候就是公平锁了。


Semaphore内部基于AQS的共享模式,所以实现都委托给了Sync类。 (原理其实大家可以自行参照源码,也比较简单)


new Semaphore(1)可以利用这个,间接实现单例模式


Semaphore总结


Semaphore主要用于控制当前活动线程数目,就如同停车场系统一般,而Semaphore则相当于看守的人,用于控制总共允许停车的停车位的个数。虽然我们自己也可以通过lock等手动来控制,但既然JUC为我们提供了便捷的工具,为何不使用呢?


Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。


相关面试题


解释一下CountDownLatch概念?


CountDownLatch 和CyclicBarrier的不同之处?


给出一些CountDownLatch使用的例子?


CountDownLatch 类中主要的方法?


说说你对Semaphore的理解,可以写一个示例吗?

相关文章
|
2月前
|
Java
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
101 9
|
3月前
|
监控 Java 测试技术
Java开发现在比较缺少什么工具?
【10月更文挑战第15天】Java开发现在比较缺少什么工具?
42 1
|
2月前
|
SQL Java 索引
java小工具util系列2:字符串工具
java小工具util系列2:字符串工具
157 83
|
22天前
|
人工智能 自然语言处理 Java
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
FastExcel 是一款基于 Java 的高性能 Excel 处理工具,专注于优化大规模数据处理,提供简洁易用的 API 和流式操作能力,支持从 EasyExcel 无缝迁移。
103 9
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
|
1月前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
83 6
Spring Boot 入门:简化 Java Web 开发的强大工具
|
2月前
|
Java 数据库
java小工具util系列1:日期和字符串转换工具
java小工具util系列1:日期和字符串转换工具
67 26
|
2月前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
64 24
|
2月前
|
Java
Java之CountDownLatch原理浅析
本文介绍了Java并发工具类`CountDownLatch`的使用方法、原理及其与`Thread.join()`的区别。`CountDownLatch`通过构造函数接收一个整数参数作为计数器,调用`countDown`方法减少计数,`await`方法会阻塞当前线程,直到计数为零。文章还详细解析了其内部机制,包括初始化、`countDown`和`await`方法的工作原理,并给出了一个游戏加载场景的示例代码。
Java之CountDownLatch原理浅析
|
2月前
|
数据采集 存储 监控
Java爬虫:数据采集的强大工具
在数据驱动的时代,Java爬虫技术凭借其强大的功能和灵活性,成为企业获取市场信息、用户行为及竞争情报的关键工具。本文详细介绍了Java爬虫的工作原理、应用场景、构建方法及其重要性,强调了在合法合规的前提下,如何有效利用Java爬虫技术为企业决策提供支持。
|
3月前
|
存储 消息中间件 安全
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
【10月更文挑战第9天】本文介绍了如何利用JUC组件实现Java服务与硬件通过MQTT的同步通信(RRPC)。通过模拟MQTT通信流程,使用`LinkedBlockingQueue`作为消息队列,详细讲解了消息发送、接收及响应的同步处理机制,包括任务超时处理和内存泄漏的预防措施。文中还提供了具体的类设计和方法实现,帮助理解同步通信的内部工作原理。
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)