首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Semaphore 信号量如何实现文件导出限流?

情景导入

我想各位小伙伴一定都做过导出功能,就算没做过,那肯定也用过。

如果你既没有吃过猪肉,也没有见过猪跑。那这篇文章也可以读一读,可以补充点知识。

导出作为一个非常常见的功能,也是稍有不慎就会导致系统压力剧增的问题之一。

有类似苦恼的小伙伴可以阅读下我以前写的文章:

java 导出 excel 最佳实践,java 大文件 excel 避免OOM(内存溢出) excel 工具框架

cpu 又报警了,快看看为什么?

记得前不久,一个本该和平的上午,报警群里忽然就炸了,报警信息不断地轰炸过来。

“快看看怎么了?”,项目经理赶紧让各位同事查查问题。

“CPU 太高了”,查了下,有人回到,“不知道是谁在一直导出大文件。”

我们知道 excel 的导出是非常消耗较器性能的,为了限制范围,以前已经加了时间范围 1 个月,还做了很多优化。

但是现在操作员可能在同时导出,导致机器压力还是太大了。

“看一下能不能解决这个问题”,项目经理说,“这么报警也不是办法。”

怎么解决?

各位小伙伴,如果是你来解决这个问题,你会怎么做呢?

我们今天来介绍一种比较常用的解决方案,需要用到今天的主角 Semaphore 信号量。

小伙伴有其他想法也欢迎评论区和大家分享讨论一下。

Semaphore 介绍

计数信号量(Counting Semaphore)用来控制同时访问的某个特定资源的操作数量,或者同时执行某个指定操作的数量

ps: 我们可以根据这个特性,灵活地限制同时导出的执行数量。

计算信号量还可以用来实现某种资源池,或者对容器施加边界。

Semaphore 中管理着一组虚拟许可(permit),许可的初始量可通过构造函数来指定。

在执行操作时可以首先获得许可(只要还有剩余的许可),并在使用以后释放许可。

如果没有许可,那么acquire将阻塞直到有许可(或者直到被中断或者操作超时)。

release方法将返回一个许可给信号量。计算信号量的一种简化形式是二值信号量,即初始化值为1的Semaphore。二值信号量可以用做互斥体(mutex),并具备不可重入的加锁语义:谁拥有这个唯一的许可,谁就拥有了互斥锁。

使用例子

使用说明

声明信号量:

获取许可:

释放许可:

测试日志

可以看到一开始前 5 个客户端都拿到了访问权限,但是后面的就需要等待了。

等到后面逐渐释放锁,锁的 又恢复到了 5 个。

源码解析

jdk 版本

不同的 jdk 版本源码可能存在差异,老马这次梳理的 jdk 信息如下:

类定义

Semaphore 实现了 Serializable 接口。

Sync 是整个实现最核心的部分。

通过构造器可以看到,支持是否为公平锁。

和可重入锁的设计看起来有些类似。

Sync 实现

继承自 AQS 类,简单介绍直接写在了注释中。

非公平锁实现

非公平锁的 tryAcquireShared 就是直接调用 Sync 中的方法。

公平锁实现

如何实现公平锁模式呢?

其实答案就是按顺序排队,谁插队,用吐沫星子淹死他

这里都是通过父类的 hasQueuedPredecessors 方法,如果前面有人排队,直接返回获取失败。

如果已经排到我了,则计算剩余的量,然后通过 CAS 设置。

获取锁

获取锁

获取锁实际上调用的还是 方法。

这个是 AQS 中的方法,

尝试获取锁

这个和可重入锁中的实现实际上非常类似,注意这里调用的是非公平获取锁的模式。

可以根据我们指定是否公平尝试获取锁:

这个方法对应的就是我们指定的 NoFairSync 或者 FairSync 对象了。

指定获取信号量的个数

默认是获取 1 个信号量,我们也可以指定获取的个数。

当然也有同时指定信号量个数+超时时间的方法:

实际上这里就体现了一个问题,就叫做接口爆炸

jdk 为了使用者的便利性,对一个基础的方法,提供了大量的封装方法,本质上实际只有一个方法。

锁释放

统一调用的是 releaseShared 方法,实际上参数为 1。

当然参数如果允许用户自定义,就需要添加一个判断。

其他方法

主要讲述下和 Sync 对象有关的几个方法,不能让我们前面 Sync 源码讲解浪费了。

这里就是对 Sync 对应方法的简单调用。

小结

Semaphore 作为一个并发的控制工具,使用起来非常的方便,实现的原理非常类似可重入锁,都是继承自 AQS 类。

希望本文对你有帮助,如果有其他想法的话,也可以评论区和大家分享哦。

各位极客的点赞收藏转发,是老马持续写作的最大动力!

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20201111A0GLY800?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券