【漏斗桶】


import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 漏桶算法工具类
 */
public class BucketLimitUtil {
    public static final Map<String, Funnel> funnelMap = new ConcurrentHashMap<>();

    /**
     * 根据给定的漏斗参数检查是否允许访问
     *
     * @param capacity   漏斗容量
     * @param allowQuota 每单个单位时间允许的流量
     * @param perSecond  单位时间(秒)
     * @param key        funnelMap中key值
     * @return 是否允许访问
     */
    public static boolean isActionAllowed(int capacity, int allowQuota, int perSecond, String key) {
//        String key = "funnelKey";
        if (!funnelMap.containsKey(key)) {
            funnelMap.put(key, new Funnel(capacity, allowQuota, perSecond));
        }
        Funnel funnel = funnelMap.get(key);
        return funnel.watering(1);
    }

    private static class Funnel {
        //容量
        private final int capacity;
        //泄露率
        private final float leakingRate;
        //剩余流量
        private int leftQuota;
        //
        private long leakingTs;

        private int restoreQuota;

        /**
         * @param capacity  漏斗容量
         * @param count     每单个单位时间允许的流量
         * @param perSecond 单位时间(秒)
         */
        public Funnel(int capacity, int count, int perSecond) {
            this.capacity = capacity;
            // 因为计算使用毫秒为单位的
            perSecond *= 1000;
            this.leakingRate = (float) count / perSecond;
        }

        /**
         * 根据上次水流动的时间,腾出已流出的空间
         */
        private void makeSpace() {
            long now = System.currentTimeMillis();
            long time = now - leakingTs;
            int leaked = (int) (time * leakingRate);
            if (leaked < 1) {
                return;//表示超出速率
            }
            leftQuota += leaked;
            restoreQuota += leaked;
            // 如果剩余大于容量,则剩余等于容量
            if (leftQuota > capacity) {
                leftQuota = capacity;
            }
            if (restoreQuota > capacity) {
                restoreQuota = 0;
                leftQuota = capacity;
            }

            leakingTs = now;
        }

        /**
         * 漏斗漏水
         *
         * @param quota 流量
         * @return 是否有足够的水可以流出(是否允许访问)
         */
        public boolean watering(int quota) {
            makeSpace();
            int left = leftQuota - quota;
            if (left >= 0) {
                leftQuota = left;
                return true;
            }
            return false;
        }
    }

    public static void clear(String key) {
        Funnel funnel = funnelMap.remove(key);
    }
}

  • 15
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值