基于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. 没超限制 -> 更新次数

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现过期时间的缓存,可以使用 `ConcurrentHashMap` 结合 `ScheduledExecutorService` 来实现。 首先,使用 `ConcurrentHashMap` 存储缓存的键值对,键为缓存的 key,值为缓存的 value。 然后,使用 `ScheduledExecutorService` 定时清除过期的缓存。可以通过定时任务调度线程池来实现。 下面是一个简单的示例代码: ```java import java.util.Map; import java.util.concurrent.*; public class ExpiringCache<K, V> { private final Map<K, V> cache; private final ScheduledExecutorService scheduler; public ExpiringCache() { this.cache = new ConcurrentHashMap<>(); this.scheduler = Executors.newSingleThreadScheduledExecutor(); } // 添加缓存项 public void put(K key, V value, long expireTimeMillis) { cache.put(key, value); // 在指定时间后清除缓存项 scheduler.schedule(() -> cache.remove(key), expireTimeMillis, TimeUnit.MILLISECONDS); } // 获取缓存项 public V get(K key) { return cache.get(key); } // 移除缓存项 public void remove(K key) { cache.remove(key); } } ``` 使用示例: ```java ExpiringCache<String, String> cache = new ExpiringCache<>(); cache.put("key1", "value1", 5000); // 缓存项在5秒后过期 cache.put("key2", "value2", 10000); // 缓存项在10秒后过期 String value1 = cache.get("key1"); // 获取缓存项,如果过期则返回 null String value2 = cache.get("key2"); System.out.println(value1); // 输出:value1 System.out.println(value2); // 输出:value2 Thread.sleep(6000); String expiredValue = cache.get("key1"); System.out.println(expiredValue); // 输出:null,缓存项已过期 ``` 注意,该示例代码只是一个简单的实现,没有考虑并发情况下的线程安全性和性能优化,如果在实际项目中使用,请根据需求进行适当的改进。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值