Java令牌桶API实现了没

wen java案例 3

本文目录导读:

Java令牌桶API实现了没

  1. 使用第三方库(推荐)
  2. 自己实现(简单示例)
  3. 使用 Java 并发工具 + 定时器
  4. 企业级方案

截至2025年5月,Java标准库(JDK)中没有内置现成的令牌桶(Token Bucket)算法API,但可以通过以下几种方式实现:


使用第三方库(推荐)

Google Guava(最常用)

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>33.2.0-jre</version>
</dependency>
// 创建令牌桶 - 每秒2个令牌
RateLimiter limiter = RateLimiter.create(2.0); // 每秒产生2个令牌
// 尝试获取令牌(阻塞)
double waitTime = limiter.acquire(); // 获取1个令牌,等待直到获取成功
// 尝试获取令牌(非阻塞)
boolean acquired = limiter.tryAcquire(); // 立即返回
boolean acquired = limiter.tryAcquire(5, TimeUnit.SECONDS); // 最多等待5秒

Guava RateLimiter 特点

  • 基于令牌桶算法(实际上是漏斗算法的变体)
  • 支持平滑突发(SmoothBursty)和预热(SmoothWarmingUp)
  • 支持预消费

自己实现(简单示例)

public class TokenBucket {
    private final long capacity;        // 桶容量
    private final double refillRate;    // 每秒生成的令牌数
    private double tokens;              // 当前令牌数
    private long lastRefillTimestamp;   // 上次刷新时间
    public TokenBucket(long capacity, double refillRate) {
        this.capacity = capacity;
        this.refillRate = refillRate;
        this.tokens = capacity;
        this.lastRefillTimestamp = System.nanoTime();
    }
    public synchronized boolean tryConsume(int tokens) {
        refill();
        if (this.tokens >= tokens) {
            this.tokens -= tokens;
            return true;
        }
        return false;
    }
    private void refill() {
        long now = System.nanoTime();
        double tokensToAdd = (now - lastRefillTimestamp) * refillRate / 1_000_000_000.0;
        this.tokens = Math.min(capacity, this.tokens + tokensToAdd);
        this.lastRefillTimestamp = now;
    }
}
// 使用
TokenBucket bucket = new TokenBucket(10, 2); // 容量10,每秒2个令牌
boolean success = bucket.tryConsume(1);       // 尝试获取1个令牌

使用 Java 并发工具 + 定时器

public class TokenBucketScheduled {
    private final BlockingQueue<Object> bucket;
    private final Object token = new Object();
    public TokenBucketScheduled(int capacity, int rate) {
        bucket = new LinkedBlockingQueue<>(capacity);
        // 初始化装满令牌
        for (int i = 0; i < capacity; i++) {
            bucket.offer(token);
        }
        // 定时向桶中添加令牌
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(() -> {
            bucket.offer(token); // 桶满时丢弃
        }, 0, 1000 / rate, TimeUnit.MILLISECONDS);
    }
    public boolean tryConsume() {
        return bucket.poll() != null;  // 非阻塞
    }
    public void consume() throws InterruptedException {
        bucket.take();  // 阻塞等待
    }
}

企业级方案

Resilience4j(支持令牌桶)

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-ratelimiter</artifactId>
    <version>2.2.0</version>
</dependency>
RateLimiterConfig config = RateLimiterConfig.custom()
    .limitForPeriod(10)                // 周期内允许的请求数
    .limitRefreshPeriod(Duration.ofSeconds(1)) // 刷新周期
    .timeoutDuration(Duration.ofMillis(500))   // 等待超时
    .build();
RateLimiter rateLimiter = RateLimiter.of("myService", config);
// 装饰你的函数
Supplier<String> decorated = RateLimiter.decorateSupplier(rateLimiter, () -> "result");

方案 推荐场景 是否内置
Guava RateLimiter 通用场景 ✅ 首选 第3方库
Resilience4j 微服务/异步场景 第3方库
自己实现 简单场景/学习 手动
JDK并发工具 基础控制 组合实现

Java 标准库没有直接提供令牌桶 API,但 Guava 的 RateLimiter 是最常用、最成熟的替代方案。

抱歉,评论功能暂时关闭!