Java 实现令牌桶限流算法 原生极简实现 包括单机和多线程版本

2023-11-20

令牌桶算法简介

令牌桶是指一个限流容器,容器有最大容量,每秒或每100ms产生一个令牌(具体取决于机器每秒处理的请求数),当容量中令牌数量达到最大容量时,令牌数量也不会改变了,只有当有请求过来时,使得令牌数量减少(只有获取到令牌的请求才会执行业务逻辑),才会不断生成令牌,所以令牌桶算法是一种弹性的限流算法

限流完下一步我们可以做什么呢,限流完后所有请求都是获取令牌的,都是我们要执行的,但是如果还有很多请求,这时我们要有一个方式决定怎样执行这些请求,这个方式称为调度,可以看我这篇文章 调度算法

令牌桶算法限流范围:

假设令牌桶最大容量为n,每秒产生r个令牌

  1. 平均速率:则随着时间推延,处理请求的平均速率越来越趋近于每秒处理r个请求,说明令牌桶算法可以控制平均速率
  2. 瞬时速率:如果在一瞬间有很多请求进来,此时来不及产生令牌,则在一瞬间最多只有n个请求能获取到令牌执行业务逻辑,所以令牌桶算法也可以控制瞬时速率

在这里提下漏桶,漏桶由于出水量固定,所以无法应对突然的流量爆发访问,也就是没有保证瞬时速率的功能,但是可以保证平均速率

单机版实现

  1. capacity为当前令牌桶的中令牌数量,timeStamp为上一次请求获取令牌的时间,我们没必要真的实现计时器每秒产生多少令牌放入容器中,只要记住上一次请求到来的时间,和这次请求的差值就知道在这段时间内产生了多少令牌
  2. 下面假设100ms产生1个令牌,且令牌桶最大容量为10
  3. Thread.sleep是模拟不同请求到来的间隔,改变间隔可以看到不同现象
public class LeakyBucketAlgorithm {
    private int capacity = 10;
    private long timeStamp = System.currentTimeMillis();

    public boolean getToken() {
        if (capacity > 0) {
            capacity--;
            return true;
        }
        long current = System.currentTimeMillis();
        if (current - timeStamp >= 100) {
            if ((current - timeStamp) / 100 >= 2) {
            	// 假设100ms产生一个令牌
                capacity += (int)((current - timeStamp) / 100) - 1;
            }
            timeStamp = current;
            if (capacity > 10) capacity = 10;
            return true;
        }
        return false;
    }

    public static void main(String[] args) throws InterruptedException {
        LeakyBucketAlgorithm leakyBucketAlgorithm = new LeakyBucketAlgorithm();
        while (true) {
//            Thread.sleep(10);
            Thread.sleep(100);
            if (leakyBucketAlgorithm.getToken()) {
                System.out.println("获取令牌成功,可以执行业务逻辑了");
            } else {
                System.out.println("获取令牌失败,请稍后重试");
            }
        }
    }
}

多线程版实现

  1. 多线程实现也非常简单,只要在方法加一个同步锁,保证同时只有一个请求能尝试获取令牌就可以了
  2. Thread.sleep(1000)是因为有10个线程在抢令牌,而每100ms才产生一个令牌,所以每隔1秒抢一次,可以改变这个值看现象
public class LeakyBucketAlgoritmThread {
    private int capacity = 10;
    private long timeStamp = System.currentTimeMillis();


    public synchronized boolean getToken() {
        if (capacity > 0) {
            capacity--;
            return true;
        }
        long current = System.currentTimeMillis();
        if (current - timeStamp >= 100) {
            if ((current - timeStamp) / 100 >= 2) {
                capacity += (int)((current - timeStamp) / 100) - 1;
            }
            timeStamp = current;
            if (capacity > 10) capacity = 10;
            return true;
        }
        return false;
    }

    public static void main(String[] args) throws InterruptedException {
        LeakyBucketAlgoritmThread leakyBucketAlgorithmThread = new LeakyBucketAlgoritmThread();
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        try {
//                            Thread.sleep(900);
                            Thread.sleep(1000);
                            if (leakyBucketAlgorithmThread.getToken()) {
                                System.out.println(Thread.currentThread().getName()+" 获取令牌成功,可以执行业务逻辑了");
                            } else {
                                System.out.println(Thread.currentThread().getName()+" 获取令牌失败,请稍后重试");
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 实现令牌桶限流算法 原生极简实现 包括单机和多线程版本 的相关文章

随机推荐

  • 交叉连接查询课程号

  • C++的引用

    C 的引用 一 什么是引用 1 1声明方法 1 2为什么C 要加入引用类型的变量 引用类型与指针类型的比较 二 引用类型在函数中的实际使用 2 1传参数时特殊情况 临时变量 三 引用的更多使用 3 1 常引用 C 引用就是一个变量的别名 一
  • Java实现文件传输

    Java实现文件传输 在Java编程中 我们可以使用各种方法实现文件传输 文件传输是将文件从一个位置传输到另一个位置的过程 可以用于各种应用场景 如文件备份 文件共享等 下面我将介绍一种基于Socket的Java文件传输实现方法 首先 我们
  • C++程序中使用openpose预测关节点坐标的简易实现

    C 程序中使用openpose预测关节点坐标的简易实现 虽然在openpose的官网上已经给出了很多可用的demo 但是如果我们在自己的C 项目中想要使用openpose来预测三维关键点官网给出的例子不是很适用 所以我现在给出了C 程序中使
  • Go切片排序

    Go 语言标准库提供了sort包 用于对切片和用户定义的集合进行排序 具体示例如下 基本排序 package main import fmt sort func main float 从小到大排序 f float64 5 2 1 3 0 7
  • 解决elementUI的对话框(Dialog)组件点击自动跳转到页面顶部问题

  • Python身份运算符(is , is not) 和比较运算符(==,!=)区别

    学习的时候无意中翻到 就在这里稍微记录一下 从名字上看 身份运算符的意思是 运算 两个对象的身份的 那怎么 运算 两个对象的身份呢 那么就自然而然想到比较两个对象的身份是否是相同的 在这里的身份就是他们的id 也就是内存地址 所以身份运算符
  • 【数据结构】哈夫曼编码与前缀编码

    1 前缀编码 首先对于一个串可以用等长的二进制位表示 这样就叫做固定长度编码 如果可以用不等长的二进制位表示 则称之为可变长度编码 那么对于那些频度高的字符我们采用短二进制位编码 出现频度低的采用长二进制位编码的话 将会极大地减少编码长度
  • Win2012服务器 远程桌面帐户允许多用户同时登录的配置方法(2个用户)

    打开任务栏左下角的 服务器管理器 在左侧列表中选中 本地服务器 然后将右侧 远程桌面 功能的选项修改为 启用 注意取消下面复选框的选中状态 修改本地组策略 允许远程桌面帐户的多用户访问 同时按住 Win键 R 组合键调出运行窗口 输入 gp
  • MySQL cmd窗口输入密码后闪退

    最近重新使用回 MySQL 到官网下载客户端版 MySQL Installer 进行安装时 已经设置过 root 密码为 123456 第一次用 cmd 登录时成功 然后再安装 MySQL Workbench 进行连接 却报了错误 auth
  • 基本的Java的MVC入门案例

    概念 MVC Model View Controller 模型 视图 控制器 他是一种专门设计web程序的模式 高内聚 低耦合 高内聚 专人干专事 低耦合 让类与类之间的关系不能太紧密 模型 Model 是应用程序中与处理应用程序数据逻辑的
  • React抽离组件到独立的JS文件中

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 React学习记录 一 抽离组件到独立的JS文件中 1 先创建一个Hello js 2 再创建一个index js文件 React学习记录 一 抽离组件到独立的JS
  • PHP is_array()函数详解,PHP判断是否为数组

    作者主页 士别三日wyx 作者简介 CSDN top100 阿里云博客专家 华为云享专家 网络安全领域优质创作者 推荐专栏 对网络安全感兴趣的小伙伴可以关注专栏 网络安全入门到精通 is array 一 基本使用 二 空数组 三 同时判断多
  • 字节对齐规则和位域

    字节对齐规则 结构体的起始存储位置必须是能够被该结构体中最大的数据类型所整除 每个数据成员存储的起始位置是自身大小的整数倍 比如int在32位机为4字节 则int型成员要从4的整数倍地址开始存储 结构体总大小 也就是sizeof的结果 必须
  • matlab 因果分析,matlab非参数的格兰杰因果分析

    代码1 deseason m function rp vp deseason data textdata days flipud textdata 1 days days 1 end 1 volume flipud data 5 price
  • Vue如何将数据显示在页面中

    如何将data的数据显示在页面中 1 文本插值 div msg div 渲染结果 div hello world div 2 原始HTML插值 v html v text 区别 v text不会对标签进行转义而v html会对标签进行一次转
  • QT笔记——初识QHostInfo、QHostAddress、QNetworkInterface

    网络模块需要在 pro文件中添加 QT network QHostInfo 利用操作系统提供的查询机制来查询与特定主机名相关联的主机的 IP 地址 头文件 include
  • Js中的defer属性和async属性

    Js中的defer属性和async属性 一 defer和async 1 defer 指外部js文件和当前html页面同时加载 异步加载 但只在当前页面解析完成之后执行js代码 async 指外部js文件和当前html页面同时加载 异步加载
  • Redhat Add and Remove Software[No Groups Available in any repository ]

    在 etc yum repos d中把rhel debuginfo repo 修改一下 enabled 1 修改为 enabled 1
  • Java 实现令牌桶限流算法 原生极简实现 包括单机和多线程版本

    文章目录 令牌桶算法简介 令牌桶算法限流范围 单机版实现 多线程版实现 令牌桶算法简介 令牌桶是指一个限流容器 容器有最大容量 每秒或每100ms产生一个令牌 具体取决于机器每秒处理的请求数 当容量中令牌数量达到最大容量时 令牌数量也不会改