Java常见的限流方案及实现方法

 更新时间:2025年05月23日 08:30:30   作者:SHENKEM  
高并发场景中限流是保护系统的重要手段,涵盖计数器、滑动窗口、漏桶、令牌桶等算法,这篇文章主要介绍了Java常见的限流方案及实现的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

在高并发场景中,限流(Rate Limiting) 是一种重要的保护机制,用于控制系统的请求流量,避免系统过载。以下是常见的限流方案及其 Java 实现。

1. 限流的常见算法

1.1 计数器算法

  • 原理:在固定时间窗口内统计请求次数,超过阈值则拒绝请求。

  • 优点:实现简单。

  • 缺点:无法应对突发流量。

1.2 滑动窗口算法

  • 原理:将时间窗口划分为多个小窗口,统计最近一段时间内的请求次数。

  • 优点:比计数器算法更平滑。

  • 缺点:实现复杂。

1.3 漏桶算法

  • 原理:请求以固定速率流出,超过桶容量的请求被丢弃或等待。

  • 优点:平滑流量。

  • 缺点:无法应对突发流量。

1.4 令牌桶算法

  • 原理:以固定速率生成令牌,请求需要获取令牌才能被处理。

  • 优点:支持突发流量。

  • 缺点:实现复杂。

2. 限流方案的 Java 实现

以下是基于 计数器算法 和 令牌桶算法 的 Java 实现示例。

2.1 计数器算法实现

import java.util.concurrent.atomic.AtomicInteger;

public class CounterRateLimiter {
    private final int limit; // 限流阈值
    private final long interval; // 时间窗口(毫秒)
    private final AtomicInteger counter; // 计数器
    private long lastResetTime; // 上次重置时间

    public CounterRateLimiter(int limit, long interval) {
        this.limit = limit;
        this.interval = interval;
        this.counter = new AtomicInteger(0);
        this.lastResetTime = System.currentTimeMillis();
    }

    public boolean tryAcquire() {
        long now = System.currentTimeMillis();
        if (now - lastResetTime > interval) {
            // 重置计数器
            counter.set(0);
            lastResetTime = now;
        }
        // 判断是否超过阈值
        return counter.incrementAndGet() <= limit;
    }

    public static void main(String[] args) throws InterruptedException {
        CounterRateLimiter limiter = new CounterRateLimiter(10, 1000); // 每秒限流 10 次
        for (int i = 0; i < 20; i++) {
            System.out.println("请求 " + i + ": " + (limiter.tryAcquire() ? "通过" : "被限流"));
            Thread.sleep(100); // 模拟请求间隔
        }
    }
}

2.2 令牌桶算法实现

import java.util.concurrent.atomic.AtomicLong;

public class TokenBucketRateLimiter {
    private final long capacity; // 桶容量
    private final long rate; // 令牌生成速率(令牌/毫秒)
    private final AtomicLong tokens; // 当前令牌数量
    private long lastRefillTime; // 上次补充令牌时间

    public TokenBucketRateLimiter(long capacity, long rate) {
        this.capacity = capacity;
        this.rate = rate;
        this.tokens = new AtomicLong(capacity);
        this.lastRefillTime = System.currentTimeMillis();
    }

    public boolean tryAcquire() {
        refillTokens(); // 补充令牌
        long currentTokens = tokens.get();
        if (currentTokens > 0) {
            return tokens.decrementAndGet() >= 0;
        }
        return false;
    }

    private void refillTokens() {
        long now = System.currentTimeMillis();
        long elapsedTime = now - lastRefillTime;
        long newTokens = elapsedTime * rate; // 计算新增令牌数
        if (newTokens > 0) {
            lastRefillTime = now;
            tokens.updateAndGet(old -> Math.min(capacity, old + newTokens)); // 更新令牌数
        }
    }

    public static void main(String[] args) throws InterruptedException {
        TokenBucketRateLimiter limiter = new TokenBucketRateLimiter(10, 1); // 桶容量 10,每秒生成 1 个令牌
        for (int i = 0; i < 20; i++) {
            System.out.println("请求 " + i + ": " + (limiter.tryAcquire() ? "通过" : "被限流"));
            Thread.sleep(100); // 模拟请求间隔
        }
    }
}

3. 使用 Guava 的 RateLimiter

Google Guava 提供了 RateLimiter 类,基于令牌桶算法实现限流。

3.1 添加依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>

运行 HTML

3.2 使用示例

import com.google.common.util.concurrent.RateLimiter;

public class GuavaRateLimiterExample {
    public static void main(String[] args) throws InterruptedException {
        RateLimiter limiter = RateLimiter.create(1.0); // 每秒限流 1 次
        for (int i = 0; i < 10; i++) {
            System.out.println("请求 " + i + ": " + (limiter.tryAcquire() ? "通过" : "被限流"));
            Thread.sleep(300); // 模拟请求间隔
        }
    }
}

4. 限流方案的选择

算法优点缺点适用场景
计数器实现简单无法应对突发流量简单限流场景
滑动窗口比计数器更平滑实现复杂需要平滑限流的场景
漏桶平滑流量无法应对突发流量需要严格控制流量的场景
令牌桶支持突发流量实现复杂需要支持突发流量的场景
Guava简单易用,功能强大依赖第三方库需要快速实现限流的场景

5. 总结

  • 限流是保护系统的重要手段,常见的限流算法包括计数器、滑动窗口、漏桶和令牌桶。

  • Java 中可以通过自定义实现或使用 Guava 的 RateLimiter 实现限流。

  • 根据业务需求选择合适的限流方案,确保系统的稳定性和高可用性。

通过以上内容,可以轻松掌握限流的实现方法!

到此这篇关于Java常见的限流方案及实现的文章就介绍到这了,更多相关Java限流方案内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java8 Collectors.toMap的坑

    Java8 Collectors.toMap的坑

    这篇文章主要介绍了Java8 Collectors.toMap的坑,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • Java多线程中的ThreadPoolExecutor使用解析

    Java多线程中的ThreadPoolExecutor使用解析

    这篇文章主要介绍了Java多线程中的ThreadPoolExecutor使用解析,作为线程池的缓冲,当新增线程超过maximumPoolSize时,会将新增线程暂时存放到该队列中,需要的朋友可以参考下
    2023-12-12
  • 关于mybatis-plus插件使用时的一些问题小结

    关于mybatis-plus插件使用时的一些问题小结

    这篇文章主要给大家介绍了关于mybatis-plus插件使用时的一些问题的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-03-03
  • SpringBoot应用jar包启动原理详解

    SpringBoot应用jar包启动原理详解

    本文主要介绍了SpringBoot应用jar包启动原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-03-03
  • Eclipse maven项目lombok安装配置图解

    Eclipse maven项目lombok安装配置图解

    这篇文章主要介绍了Eclipse maven项目lombok安装配置图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • 初识Java基础之数据类型与运算符

    初识Java基础之数据类型与运算符

    Java是一种强类型语言,每个变量都必须声明其数据类型,下面这篇文章主要给大家介绍了关于Java基础之数据类型与运算符的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2021-10-10
  • 解读Spring Bean的作用域

    解读Spring Bean的作用域

    这篇文章主要介绍了解读Spring Bean的作用域,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • Java用邻接表存储图的示例代码

    Java用邻接表存储图的示例代码

    邻接表是图的一种链式存储方法,其数据结构包括两部分:节点和邻接点。本文将用邻接表实现存储图,感兴趣的小伙伴可以了解一下
    2022-06-06
  • Java 阻塞队列BlockingQueue详解

    Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下
    2022-06-06
  • Spring Boot 集成PageHelper的使用方法

    Spring Boot 集成PageHelper的使用方法

    这篇文章主要介绍了Spring Boot 集成PageHelper的使用方法,文章内容围绕主题展开详细介绍,需要的小伙伴可以参考一下,希望对你的学习有所帮助
    2022-04-04

最新评论