通常可应用于抢购限流防止冲垮系统;限制某接口、服务单位时间内的访问量,譬如一些第三方服务会对用户访问量进行限制;限制网速,单位时间内只允许上传下载多少字节等。
下面来看一些简单的实践,需要先引入guava的maven依赖。
一 有很多任务,但希望每秒不超过N个
- 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秒会放行一个。
二 抢购场景限流
- 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 "失败";
- }