令牌桶简单实现(Java)
发布日期:2021-06-28 19:59:35
浏览次数:2
分类:技术文章
本文共 3748 字,大约阅读时间需要 12 分钟。
令牌桶简单实现(Java)
文章目录
简介
百度可得,令牌桶是一个桶,定时往里面放令牌,然后请求来了从令牌桶里取令牌,取到了继续后续逻辑,没取到就拦截不让请求,达到限流目的实现思路
参考了guava的RateLimiter之后,发现并没有“一个线程定时往桶里放token”,而是在请求进来时通过当前时间戳实时计算(下一次加令牌的时间为x,此时时间为m,平均n秒放一个令牌,则此时应当增加 (m - x) / n + 1 个令牌)
code
/** * 令牌桶 * 局限:最多1毫秒生成一个令牌 * * create time: 2020/7/15 9:42 */public class TokenBucket { private final double unitAddNum; // 单位时间(1s)往桶中放令牌数量 private final long maxTokenNum; // 桶中最大有多少令牌 private volatile long currentTokenCount = 0; // 当前桶中有多少令牌 private volatile long nextRefreshTime = 0L; // 下一次刷新桶中令牌数量的时间戳 private volatile long lastAcquireTime; // 上一次从桶中获取令牌的时间戳(貌似用不到) /** * * @param unitAddNum 1秒增加几个令牌 * @param maxToken 桶中最大令牌数 * @param isFullStart 一开始是否是满的 */ public TokenBucket(double unitAddNum, long maxToken, boolean isFullStart) { if (unitAddNum <= 0 || maxToken <= 0) { throw new RuntimeException("unitAddNum and maxToken can't less than 0"); } if (unitAddNum > 1000) { throw new RuntimeException("unitAddNum max is 1000"); } this.unitAddNum = unitAddNum; this.maxTokenNum = maxToken; if (isFullStart) { this.currentTokenCount = maxToken; } else { this.currentTokenCount = 0; } this.nextRefreshTime = calculateNextRefreshTime(System.currentTimeMillis()); } public boolean acquire(long needTokenNum) { if (needTokenNum > this.maxTokenNum) { return false; } synchronized (this) { long currentTimestamp = System.currentTimeMillis(); this.refreshCurrentTokenCount(currentTimestamp); if (needTokenNum <= this.currentTokenCount) { return this.doAquire(needTokenNum, currentTimestamp); } return false; } } private boolean doAquire(long needTokenNum, long currentTimestamp) { this.currentTokenCount -= needTokenNum; this.lastAcquireTime = currentTimestamp; return true; } /** * 刷新桶中令牌数量 * @param currentTimestamp */ private void refreshCurrentTokenCount(long currentTimestamp) { if (this.nextRefreshTime > currentTimestamp) { return; } this.currentTokenCount = Math.min(this.maxTokenNum, this.currentTokenCount + calculateNeedAddTokenNum(currentTimestamp)); this.nextRefreshTime = calculateNextRefreshTime(currentTimestamp); } /** * 计算当前需要添加多少令牌 * @param currentTimestamp * @return */ private long calculateNeedAddTokenNum(long currentTimestamp) { if (this.nextRefreshTime > currentTimestamp) { return 0; } long addOneMs = Math.round(1.0D / this.unitAddNum * 1000D); // 这么久才能加1个令牌 return (currentTimestamp - this.nextRefreshTime) / addOneMs + 1; } private long calculateNextRefreshTime(long currentTimestamp) { if (currentTimestamp < this.nextRefreshTime) { return this.nextRefreshTime; } long addOneMs = Math.round(1.0D / this.unitAddNum * 1000D); // 这么久才能加1个令牌 long result = 0; if (this.nextRefreshTime <= 0) { result = currentTimestamp + addOneMs; } else { result = this.nextRefreshTime + ((currentTimestamp - this.nextRefreshTime) / addOneMs + 1) * addOneMs; } return result; } public static void main(String[] args) throws InterruptedException { TokenBucket tokenBucket = new TokenBucket(1D, 1, true); for (int i=0; i<10; i++) { System.out.println(tokenBucket.acquire(1)); Thread.sleep(500); } }}
main输出结果
truefalsetruefalsetruefalsetruefalsetruefalse
转载地址:https://blog.csdn.net/xxxxssss12/article/details/107359477 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
感谢大佬
[***.8.128.20]2024年04月11日 02时29分32秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
将excel中的数据导入到DataTable中
2019-04-29
Web页面取得当前日期
2019-04-29
让整个table居于页面正中,(上下左右居中)。
2019-04-29
wince 截全屏、截屏工具
2019-04-29
C# 中的回车换行符
2019-04-29
C#WinCE 记录日志文件
2019-04-29
C# 读写XML文件,用于配置文件
2019-04-29
PC端到WinCE端文件互相拷贝
2019-04-29
遍历文件夹及子文件夹中的所有文件
2019-04-29
MVC 实现数据导入Excel,并在客户端下载。
2019-04-29
Jquery 实现文本框键盘回车事件
2019-04-29
JQuery 循环读取table中的数据
2019-04-29
MVC刷新页面,手动刷新和自动刷新
2019-04-29
C#发送邮件
2019-04-29
JQuery实现checkbox全选和取消全选
2019-04-29
使<select>可输入
2019-04-29
JQuery正则表达式
2019-04-29
android通过webservice访问SqlServer
2019-04-29
<select>中文乱码
2019-04-29
html 文字和图片实现自适应
2019-04-29