Guava 使用 RateLimiter 限速


#Java Guava 库#


RateLimiter 是基于令牌桶实现的限速。

示例1:匀速执行

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

import java.time.LocalTime;

public class RateLimiterTest {

    public static void main(String[] args) {
        RateLimiter rateLimiter = RateLimiter.create(5);
        for (int i=0; i< 10; i++) {
            rateLimiter.acquire();
            System.out.println(LocalTime.now());
        }
    }

}

运行结果:

10:23:53.612
10:23:53.741
10:23:53.940
10:23:54.137
10:23:54.335
10:23:54.538
10:23:54.737
10:23:54.935
10:23:55.135
10:23:55.339

可以看到,基本是相隔200ms打印一次时间。

这里第一次和第二次之间相隔的是 130ms ,但是下面的示例中又说明的确过了 200ms 左右。为什么 ? 待分析。

acquire 方法会返回秒级的耗时:

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

public class RateLimiterTest {

    public static void main(String[] args) {
        RateLimiter rateLimiter = RateLimiter.create(5);
        for (int i=0; i< 10; i++) {
            double timeCost = rateLimiter.acquire();
            System.out.println("获取令牌耗时(单位秒): " + timeCost);
        }
    }

}

运行结果示例:

获取令牌耗时(单位秒): 0.0
获取令牌耗时(单位秒): 0.198251
获取令牌耗时(单位秒): 0.197075
获取令牌耗时(单位秒): 0.195677
获取令牌耗时(单位秒): 0.19635
获取令牌耗时(单位秒): 0.196841
获取令牌耗时(单位秒): 0.195845
获取令牌耗时(单位秒): 0.194625
获取令牌耗时(单位秒): 0.199044
获取令牌耗时(单位秒): 0.1966

示例2:突发流量

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

import java.util.concurrent.TimeUnit;

public class RateLimiterTest {

    public static void main(String[] args) {
        RateLimiter rateLimiter = RateLimiter.create(5);
        System.out.println("sleep 5秒");
        Uninterruptibles.sleepUninterruptibly(5, TimeUnit.SECONDS);
        for (int i=0; i< 10; i++) {
            double timeCost = rateLimiter.acquire();
            System.out.println("获取令牌耗时(单位秒): " + timeCost);
        }
    }

}

运行结果:

获取令牌耗时(单位秒): 0.0
获取令牌耗时(单位秒): 0.0
获取令牌耗时(单位秒): 0.0
获取令牌耗时(单位秒): 0.0
获取令牌耗时(单位秒): 0.0
获取令牌耗时(单位秒): 0.0
获取令牌耗时(单位秒): 0.196621
获取令牌耗时(单位秒): 0.197801
获取令牌耗时(单位秒): 0.199491
获取令牌耗时(单位秒): 0.200235

RateLimiter.create(5) 指定每秒匀速产生 5 个令牌,且令牌桶中最多5个令牌。

示例代码中获取的前5个令牌是之前颁发的已经在令牌桶中的令牌,所以获取的很快,几乎是同一时间旧全部拿出了。

示例3:预热限速

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

import java.util.concurrent.TimeUnit;

public class RateLimiterTest {

    public static void main(String[] args) {

        RateLimiter rateLimiter = RateLimiter.create(2, 3, TimeUnit.SECONDS);
        for (int i=0; i< 10; i++) {
            double timeCost = rateLimiter.acquire();
            System.out.println("获取令牌耗时(单位秒): " + timeCost);
        }
    }

}

执行结果示例:

获取令牌耗时(单位秒): 0.0
获取令牌耗时(单位秒): 1.331039
获取令牌耗时(单位秒): 0.996633
获取令牌耗时(单位秒): 0.664236
获取令牌耗时(单位秒): 0.496114
获取令牌耗时(单位秒): 0.496574
获取令牌耗时(单位秒): 0.498551
获取令牌耗时(单位秒): 0.49505
获取令牌耗时(单位秒): 0.498739
获取令牌耗时(单位秒): 0.499335

可以看到,耗时是逐步减少到500ms左右。


( 本文完 )