java单机滑动窗口限流器的实现

 更新时间:2026年03月22日 14:59:59   作者:编码忘我  
本文主要介绍了java单机滑动窗口限流器的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

下面使用 ConcurrentHashMap + ConcurrentLinkedDeque 实现一个滑动窗口限流器,限制在 10 秒内最多 N 次请求(例如 5 次)。这种方案只依赖本地内存,适合单机限流场景。

实现原理

  • 为每个用户(或 IP)维护一个 双端队列,存储每次请求的时间戳(毫秒)。

  • 每次请求时,先清理队列中 超过 10 秒 的旧时间戳,再判断队列大小是否小于阈值:

    • 若小于,则添加当前时间戳,返回 允许
    • 否则,返回 限流
  • 使用 ConcurrentHashMap 保证对用户 Key 的线程安全,使用 synchronized 对每个队列做同步,避免并发修改。

代码实现

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.TimeUnit;
/**
 * 基于 Map 的滑动窗口限流器(10秒限频)
 */
public class LocalSlidingWindowRateLimiter {
    // 存储每个用户的请求时间戳队列
    private final Map<String, ConcurrentLinkedDeque<Long>> userQueueMap = new ConcurrentHashMap<>();
    private final int windowSeconds;   // 窗口大小(秒)
    private final int maxRequests;     // 窗口内最大请求数
    public LocalSlidingWindowRateLimiter(int windowSeconds, int maxRequests) {
        this.windowSeconds = windowSeconds;
        this.maxRequests = maxRequests;
    }
    /**
     * 检查是否允许请求
     * @param key 限流标识(如 userId、ip)
     * @return true 允许,false 被限流
     */
    public boolean allowRequest(String key) {
        long now = System.currentTimeMillis();
        long windowStart = now - TimeUnit.SECONDS.toMillis(windowSeconds);
        // 获取或创建该用户的队列
        ConcurrentLinkedDeque<Long> deque = userQueueMap.computeIfAbsent(key,
                k -> new ConcurrentLinkedDeque<>());
        // 对队列加锁,保证清理和添加的原子性
        synchronized (deque) {
            // 1. 清理过期记录(窗口外的旧时间戳)
            while (!deque.isEmpty() && deque.peekFirst() < windowStart) {
                deque.pollFirst();
            }
            // 2. 判断是否超过阈值
            if (deque.size() < maxRequests) {
                // 允许请求,记录当前时间戳
                deque.addLast(now);
                return true;
            } else {
                return false;
            }
        }
    }
    // 可选:定期清理无数据的用户 Key,避免内存泄漏(可以用 ScheduledExecutorService 定时清理)
    public void cleanEmptyKeys() {
        userQueueMap.entrySet().removeIf(entry -> entry.getValue().isEmpty());
    }
}

使用示例

public class Main {
    public static void main(String[] args) throws InterruptedException {
        // 限流规则:10秒内最多5次请求
        LocalSlidingWindowRateLimiter limiter = new LocalSlidingWindowRateLimiter(10, 5);
        String userId = "user_123";
        for (int i = 0; i < 10; i++) {
            boolean allowed = limiter.allowRequest(userId);
            System.out.println("请求 " + (i + 1) + ":" + (allowed ? "通过" : "限流"));
            Thread.sleep(1000); // 模拟间隔 1 秒
        }
    }
}

输出示例(第 6 次请求被限流,因为 10 秒内已有 5 次):

请求 1:通过
请求 2:通过
请求 3:通过
请求 4:通过
请求 5:通过
请求 6:限流
请求 7:限流
...

注意事项

  1. 内存清理:长期不活动的用户 Key 会残留队列对象,建议定时调用 cleanEmptyKeys() 清理。
  2. 并发安全:每个队列使用 synchronized 锁保证原子操作,锁粒度小,性能较高。
  3. 时间精度:使用毫秒级时间戳,滑动窗口边界判断精确。
  4. 适用场景:单机应用、对分布式一致性要求不高的限流场景。

到此这篇关于java单机滑动窗口限流器的实现的文章就介绍到这了,更多相关java 滑动窗口限流器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springboot如何开启和关闭kafka消费

    springboot如何开启和关闭kafka消费

    在Kafka消费者中,通过关闭自动消费配置,使用自定义容器工厂,并在消费监听器上设置id,可以手动控制消费的开启和关闭,这是根据个人经验总结的方法,旨在帮助其他开发者
    2024-12-12
  • SpringCloud HystrixDashboard服务监控详解

    SpringCloud HystrixDashboard服务监控详解

    Hystrix Dashboard 是Spring Cloud中查看Hystrix实例执行情况的一种仪表盘组件,支持查看单个实例和查看集群实例,本文将对其服务监控学习
    2022-11-11
  • Mybatis-plus动态条件查询QueryWrapper的使用案例

    Mybatis-plus动态条件查询QueryWrapper的使用案例

    mybatis-plus框架功能很强大,把很多功能都集成了,下面这篇文章主要给大家介绍了关于Mybatis-plus动态条件查询QueryWrapper的使用教程,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2022-07-07
  • Java数据结构及算法实例:考拉兹猜想 Collatz Conjecture

    Java数据结构及算法实例:考拉兹猜想 Collatz Conjecture

    这篇文章主要介绍了Java数据结构及算法实例:考拉兹猜想 Collatz Conjecture,本文直接给出实现代码,代码中包含详细注释,需要的朋友可以参考下
    2015-06-06
  • IntelliJ IDEA快速创建getter和setter方法

    IntelliJ IDEA快速创建getter和setter方法

    这篇文章主要介绍了IntelliJ IDEA快速创建getter和setter方法,本文通过图文实例相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • springMVC中@RequestParam和@RequestPart的区别

    springMVC中@RequestParam和@RequestPart的区别

    本文主要介绍了springMVC中@RequestParam和@RequestPart的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-06-06
  • SpringBoot整合Spring Security构建安全的Web应用

    SpringBoot整合Spring Security构建安全的Web应用

    pring Security是一个强大的身份验证和访问控制框架,本文主要介绍了SpringBoot整合Spring Security构建安全的Web应用,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • java super关键字知识点详解

    java super关键字知识点详解

    在本篇文章里小编给大家整理的是一篇关于java super关键字知识点详解内容,有兴趣的朋友们可以参考下。
    2021-01-01
  • java使用静态关键字实现单例模式

    java使用静态关键字实现单例模式

    这篇文章主要为大家详细介绍了java使用静态关键字实现单例模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-04-04
  • Springboot拦截filter中异常的处理

    Springboot拦截filter中异常的处理

    SpringBoot提供了全局异常处理机制可以拦截所有异常,包括Filter中的异常,本文主要介绍了Springboot拦截filter中异常的处理,具有一定的参考价值,感兴趣的可以了解一下
    2023-11-11

最新评论