令牌桶的容量是c(个),令牌以速度r(个/秒)均匀的放入桐中,上个请求的时间为at(时间戳),上个请求后剩余的令牌数目为w(个),现在有个请求b对象进来了,现在请求的时间bt=now(),伪代码如上图,其中wb代表从at到bt时间段内产生的令牌数,产生的令牌数加上上次剩余的令牌数是不能大于桶容量的
Java实现代码:

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;public class BucketLimiter {/* 桶容量 */private final long c;/* 令牌放入速度 */private final int r;/* 桶初始化时间 */private final long initTime;/* 模拟redis缓存 */private final Map<String, Object> redisCache = new HashMap<>(2048);/* 请求时间redis key */public static final String REQUEST_TIME = "REQUEST_TIME";/* 请求后剩余令牌数redis key */public static final String TOKEN_REMAINS = "TOKEN_REMAINS";/*** @param c 桶容量* @param r 令牌放入速度*/public BucketLimiter(long c, int r) {this.c = c;this.r = r;this.initTime = System.currentTimeMillis();}/* 注意这里要加同步 */public synchronized boolean permit() {//获取上个请求后令牌桶状态BucketStatus status = getLastRequestBucketStatus();//上个请求时间final long at = status.getRequestTime();//上个请求后剩余令牌数long w = status.getRemains();//现请求时间final long bt = System.currentTimeMillis();//从上个请求到现在请求增加的令牌数final long wb = (bt - at)/1000 * r;System.out.println("===生产数:"+wb);//现在桶里面剩余的令牌数w = Math.min(w + wb, c);//假设每次消耗一个令牌if (w > 0) {w--;//请求时间和剩余令牌数redisCache.put(REQUEST_TIME, bt);redisCache.put(TOKEN_REMAINS, w);return true;} else {return false;}}/*** @description 获取上个请求后令牌桶状态* @author yulin.chen* @date 2021/10/26 10:27*/private BucketStatus getLastRequestBucketStatus() {Object requestTime = redisCache.get(REQUEST_TIME);Object remains = redisCache.get(TOKEN_REMAINS);if (null == requestTime) {//请求时间为空就是第一次请求,剩余数设置为0,时间设置为初始化时间return new BucketStatus(0L, this.initTime);}return new BucketStatus(Long.parseLong(String.valueOf(remains)), Long.parseLong(String.valueOf(requestTime)));}/****/public static class BucketStatus {/* 剩余令牌数 */private final Long remains;/* 请求时间 */private final Long requestTime;public BucketStatus(Long remains, Long requestTime) {this.remains = remains;this.requestTime = requestTime;}public Long getRemains() {return remains;}public Long getRequestTime() {return requestTime;}}
}

测试代码

public static void main(String[] args) throws InterruptedException {BucketLimiter limiter = new BucketLimiter(5000, 5);//生产5秒,每秒生产5个TimeUnit.SECONDS.sleep(5);for (int i = 0; i < 10000; i++) {new Thread(() -> System.out.println(Thread.currentThread().getName() + " request permit:" + limiter.permit()), "[Thread " + i + "]").start();}
}

令牌桶限流-java实现相关推荐

  1. Jedis使用lua脚本完成令牌桶限流

    Jedis使用lua脚本完成令牌桶限流 文章目录 Jedis使用lua脚本完成令牌桶限流 一.lua脚本的简单语法 二.令牌桶限流 1. 构思 2. 实现 三.Jemeter压测工具测试 一.lua脚 ...

  2. 可能要用心学高并发核心编程,限流原理与实战,分布式令牌桶限流

    实战:分布式令牌桶限流 本节介绍的分布式令牌桶限流通过Lua+Java结合完成,首先在Lua脚本中完成限流的计算,然后在Java代码中进行组织和调用. 分布式令牌桶限流Lua脚本 分布式令牌桶限流Lu ...

  3. 【秒杀系统】零基础上手秒杀系统(二):令牌桶限流 + 再谈超卖

    前言 本文是秒杀系统的第二篇,通过实际代码讲解,帮助你快速的了解秒杀系统的关键点,上手实际项目. 本篇主要讲解接口限流措施,接口限流其实定义也非常广,接口限流本身也是系统安全防护的一种措施,暂时列举这 ...

  4. ASP.NET Core中使用令牌桶限流

    在限流时一般会限制每秒或每分钟的请求数,简单点一般会采用计数器算法,这种算法实现相对简单,也很高效,但是无法应对瞬时的突发流量. 比如限流每秒100次请求,绝大多数的时间里都不会超过这个数,但是偶尔某 ...

  5. 什么是限流?为什么会限流呢?常见的限流算法【固定窗口限流、滑动窗口限流、漏桶限流、令牌桶限流】是什么呢?

    什么是限流?为什么会限流呢?常见的限流算法[固定窗口限流.滑动窗口限流.漏桶限流.令牌桶限流]是什么呢? 什么是限流? 为什么会限流? 1. 固定窗口限流算法 1.1 什么是固定窗口限流算法 1.2 ...

  6. rateLimiter令牌桶限流算法

    RateLimiter是guava提供的基于令牌桶算法的实现类,可以非常简单的完成限流特技,并且根据系统的实际情况来调整生成token的速率. 通常可应用于抢购限流防止冲垮系统:限制某接口.服务单位时 ...

  7. 基于Redis和 Lua 实现分布式令牌桶限流

    rpc-tech-stack 系列的实践文章 ~ 本文属于限流话题. 限流是一个很大的话题,准备把其中的所有限流器都实现一遍,以此也算全都写过了,到时候再用也不至于会心虚,毕竟真实写完成过.本文主要讲 ...

  8. 分布式限流实战--redis实现令牌桶限流

    这篇文章我们主要是分析一下分布式限流的玩法. 因为限流也是一个经典用法了. 1.微服务限流 随着微服务的流行,服务和服务之间的稳定性变得越来越重要.缓存.降级和限流是保护微服务系统运行稳定性的三大利器 ...

  9. 令牌桶限流之redis-cell的安装,使用,详解

    简言 1. redis使用有序集合zset也能实现简单的限流,但是只能处理几十,几百的量级,因为zset需要记录每一条信息,很占据空间.要想处理更大数量级的限流,必须使用其他方法 2. 通常的限流算法 ...

  10. 十三水算法php_基于PHP+Redis令牌桶限流

    一 .场景描述 在开发接口服务器的过程中,为了防止客户端对于接口的滥用,保护服务器的资源, 通常来说我们会对于服务器上的各种接口进行调用次数的限制.比如对于某个 用户,他在一个时间段(interval ...

最新文章

  1. Prokka:快速原核基因组、宏基因组基因注释
  2. 2021金蝶全球创见者大会成功举办, 500强企业共话EBC数字战斗力
  3. java有string这个类型吗_关于java的String类型
  4. mysql undrop_MySQL 如何对InnoDB使用Undrop来恢复InnoDB数据
  5. lda数学八卦_【技术博客】文本挖掘之LDA主题模型
  6. Less的Mixin嵌套规则
  7. UFLDL教程 -- 译文版
  8. idea2020 个性化设置
  9. IM 即时通讯实现原理
  10. Keil 5 C51与STM32
  11. 树莓派 | RSSHub+TTRSS
  12. 实验楼Linux入门:Linux用户管理
  13. 通过Excel表格批量生成汉信码
  14. 微信公众平台服务器配置时token验证失败
  15. 亚马逊抄作业,股票打折安排上
  16. MySQL_启动_Windows
  17. python爬虫 豆瓣电影
  18. 惠鑫云安全稳定为什么说澳元是高息钱银?高息钱银有哪些
  19. vue 视频播放插件vue-video-player的使用
  20. CSS餐厅小游戏练习1~32关(附答案和链接)

热门文章

  1. ROS2机器人笔记22.02.17
  2. 基于品类关系,虚拟类目如何建设? 1
  3. 2. 大数据感知与获取
  4. c++使用librdkafka kerberos认证
  5. html下拉控件 拼音检索和中文检索,bootstrap select 下拉框通过拼音搜索汉字
  6. yml格式(list)
  7. cad详图怎么画_CAD标准图框怎么画
  8. 计算机专业周记16篇,计算机专业实习周记10篇
  9. js逆向——百度翻译
  10. linux 命令 tar 打包压缩命令 date时间 命令实践