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,加入領取架構資料一起交流學習!

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