RateLimiter是guava提供的基於令牌桶算法的實現類,能夠很是簡單的完成限流特技,而且根據系統的實際狀況來調整生成token的速率。java
一般可應用於搶購限流防止沖垮系統;限制某接口、服務單位時間內的訪問量,譬如一些第三方服務會對用戶訪問量進行限制;限制網速,單位時間內只容許上傳下載多少字節等。mysql
下面來看一些簡單的實踐,須要先引入guava的maven依賴。web
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); } } }
package com.tianyalei.controller; import com.google.common.util.concurrent.RateLimiter; import com.tianyalei.model.GoodInfo; import com.tianyalei.service.GoodInfoService; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** * Created by wuwf on 17/7/11. */ @RestController public class IndexController { @Resource(name = "db") private GoodInfoService goodInfoService; RateLimiter rateLimiter = RateLimiter.create(10); @RequestMapping("/miaosha") public Object miaosha(int count, String code) { System.out.println("等待時間" + rateLimiter.acquire()); if (goodInfoService.update(code, count) > 0) { return "購買成功"; } return "購買失敗"; } @RequestMapping("/add") public Object add() { for (int i = 0; i < 100; i++) { GoodInfo goodInfo = new GoodInfo(); goodInfo.setCode("iphone" + i); goodInfo.setAmount(100); goodInfoService.add(goodInfo); } return "添加成功"; } }
/**
* tryAcquire(long timeout, TimeUnit unit)
* 從RateLimiter 獲取許可若是該許可能夠在不超過timeout的時間內獲取獲得的話,
* 或者若是沒法在timeout 過時以前獲取獲得許可的話,那麼當即返回false(無需等待)
*/
@RequestMapping("/buy")
public Object miao(int count, String code) {
//判斷可否在1秒內獲得令牌,若是不能則當即返回false,不會阻塞程序
if (!rateLimiter.tryAcquire(1000, TimeUnit.MILLISECONDS)) {
System.out.println("短時間沒法獲取令牌,真不幸,排隊也瞎排");
return "失敗";
}
if (goodInfoService.update(code, count) > 0) {
System.out.println("購買成功");
return "成功";
}
System.out.println("數據不足,失敗");
return "失敗";
}