Java多线程学习:使用Guava RateLimiter限流

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

AccessLimitService.java 限流服务封装到一个类中AccessLimitService,提供tryAcquire()方法,用来尝试获取令牌,返回true表示获取到

@Service
public class AccessLimitService {
 //每秒只发出5个令牌
 RateLimiter rateLimiter = RateLimiter.create(5.0);
 /**
 * 尝试获取令牌
 * @return
 */
 public boolean tryAcquire(){
 return rateLimiter.tryAcquire();
 }
}

Controller层每次收到请求的时候都尝试去获取令牌,获取成功和失败打印不同的信息

import com.google.common.util.concurrent.RateLimiter; 
 
import java.util.ArrayList; 
import java.util.List; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
 
/** 
 * Created by wuwf on 17/7/11. 
 * 有很多个任务,但希望每秒不超过X个,可用此类 
 */ 
public class Demo1 { 
 
 public static void main(String[] args) { 
 //0.5代表一秒最多多少个 
 RateLimiter rateLimiter = RateLimiter.create(0.5); 
 List<Runnable> tasks = new ArrayList<Runnable>(); 
 for (int i = 0; i < 10; i++) { 
 tasks.add(new UserRequest(i)); 
 } 
 ExecutorService threadPool = Executors.newCachedThreadPool(); 
 for (Runnable runnable : tasks) { 
 System.out.println("等待时间:" + rateLimiter.acquire()); 
 threadPool.execute(runnable); 
 } 
 } 
 
 private static class UserRequest implements Runnable { 
 private int id; 
 
 public UserRequest(int id) { 
 this.id = id; 
 } 
 
 public void run() { 
 System.out.println(id); 
 } 
 } 
 
} 

我们限制了2秒放行一个,可以看到第一个是直接执行了,后面的每2秒会放行一个。

rateLimiter.acquire()该方法会阻塞线程,直到令牌桶中能取到令牌为止才继续向下执行,并返回等待的时间。

RateLimiter方法摘要

  • 修饰符和类型 方法和描述
  •  
  • double acquire() 从RateLimiter获取一个许可,该方法会被阻塞直到获取到请求
  •  
  • double acquire(int permits)从RateLimiter获取指定许可数,该方法会被阻塞直到获取到请求
  •  
  • static RateLimiter create(double permitsPerSecond)根据指定的稳定吞吐率创建RateLimiter,这里的吞吐率是指每秒多少许可数(通常是指QPS,每秒多少查询)
  •  
  • static RateLimiter create(double permitsPerSecond, long warmupPeriod, TimeUnit unit)根据指定的稳定吞吐率和预热期来创建RateLimiter,这里的吞吐率是指每秒多少许可数(通常是指QPS,每秒多少个请求量),在这段预热时间内,
  •  
  • RateLimiter每秒分配的许可数会平稳地增长直到预热期结束时达到其最大速率。(只要存在足够请求数来使其饱和)
  •  
  • double getRate()返回RateLimiter 配置中的稳定速率,该速率单位是每秒多少许可数
  •  
  • void setRate(double permitsPerSecond)更新RateLimite的稳定速率,参数permitsPerSecond 由构造RateLimiter的工厂方法提供。 String toString()返回对象的字符表现形式
  •  
  • boolean tryAcquire()从RateLimiter 获取许可,如果该许可可以在无延迟下的情况下立即获取得到的话
  •  
  • boolean tryAcquire(int permits)从RateLimiter 获取许可数,如果该许可数可以在无延迟下的情况下立即获取得到的话 boolean tryAcquire(int permits, long timeout, TimeUnit unit)从RateLimiter 获取指定许可数如果该许可数可以在不超过timeout的时间内获取得到的话,或者如果无法在timeout 过期之前获取得到许可数的话,那么立即返回false (无需等待)
  •  
  • boolean tryAcquire(long timeout, TimeUnit unit)从RateLimiter 获取许可如果该许可可以在不超过timeout的时间内获取得到的话,或者如果无法在timeout 过期之前获取得到许可的话,那么立即返回false(无需等待) 举例来说明如何使用RateLimiter,想象下我们需要处理一个任务列表,但我们不希望每秒的任务提交超过两个:
  •  
//速率是每秒两个许可
final RateLimiter rateLimiter = RateLimiter.create(2.0);
void submitTasks(List tasks, Executor executor) {
 for (Runnable task : tasks) {
 rateLimiter.acquire(); // 也许需要等待
 executor.execute(task);
 }
}

官方文档:http://ifeve.com/guava-ratelimiter

Java程序员群:956058372,加入领取架构资料一起交流学习!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章