基于ConcurrentHashMap实现带时限次数限制的缓存

需求

需要实现一个对准确性要求不高的 每个客户 每小时请求次数 不超过100次的限制,用于防止接口被刷。

思考

  • 既然对准确性要求不高,那么实现一个简易高效的 web 缓存足以。
  • 缓存信息包括 客户、时间、次数,用 map 来存比较合适。

大概思路有了,正打算面向浏览器编程时,脑海里秃然非常清晰想到怎么做了,于是开开心心地写了起来。

实现

1)先有一个实体类 LimitEntity

public class LimitEntity {
    Long beginTime = 0L;
    int times = 0;

    public Long getBeginTime() {
        return beginTime;
    }

    public void setBeginTime(Long beginTime) {
        this.beginTime = beginTime;
    }

    public int getTimes() {
        return times;
    }

    public void setTimes(int times) {
        this.times = times;
    }
}

2)再有一个缓存实现类

import java.util.Calendar;
import java.util.concurrent.ConcurrentHashMap;

public class TestConcurrentHashMap {
    private static long timeLimit = 3600*1000; //时限 1小时
    private static int timesLimit = 10; //次数限制 10次
    private static ConcurrentHashMap<Integer, LimitEntity> cacheMap = new ConcurrentHashMap<Integer, LimitEntity>();
    public static void main(String[] args) {
        int aid = 1;
        for (int i=0; i<=timesLimit; i++){
            count(aid, Calendar.getInstance().getTimeInMillis());
        }
    }

    public static void count(int aid, long now){
        LimitEntity limitEntity = cacheMap.get(aid);
        int times = 1;
        if (limitEntity == null){
            //首次访问的用户,put 进缓存
            limitEntity = new LimitEntity();
            limitEntity.setBeginTime(now);
            limitEntity.setTimes(times);
            cacheMap.put(aid, limitEntity);
        }else {
            long beginTime = limitEntity.getBeginTime();
            if (now - beginTime > timeLimit){
                //超出时限1小时,重置开始时间和次数
                limitEntity.setBeginTime(now);
                limitEntity.setTimes(times);
                cacheMap.put(aid, limitEntity);
            }else {
                times = limitEntity.getTimes()+1;
                if (times > timesLimit){
                    //超出次数限制,提示
                    System.out.println("超出限制");
                    return;
                }else {
                    //没超限制,更新次数
                    limitEntity.setTimes(times);
                    cacheMap.put(aid, limitEntity);
                }
            }
        }
        System.out.println("aid=" + aid + ";now - beginTime=" + (now - limitEntity.getBeginTime()) + ";times=" + limitEntity.getTimes());
    }
}

3)主要步骤

如代码,看注释应该很好理解了。

  1. 首次访问的用户 -> put 进缓存
  2. 超出时限1小时 -> 重置开始时间和次数
  3. 超出次数限制 -> 提示
  4. 没超限制 -> 更新次数

运行效果
在这里插入图片描述
以上。如果有更优雅的办法欢迎留言讨论喔。
在这里插入图片描述

posted @ 2021-05-28 15:18  菜小鸟同学  阅读(146)  评论(3)    收藏  举报