栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

令牌桶限流-java实现

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

令牌桶限流-java实现


令牌桶的容量是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;

    
    private final Map redisCache = new HashMap<>(2048);
    
    public static final String REQUEST_TIME = "REQUEST_TIME";
    
    public static final String TOKEN_REMAINS = "TOKEN_REMAINS";

    
    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;
        }
    }

    
    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();
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/354339.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号