面试题目:如何实现限流
思路: 限制同一时间段的请求数量,即使用计数器来限制请求的数量。
请求开始加1,请求结束减1;
思路实现代码
@RestController public class Demo1_CounterTest { Counter counter = new CounterBasic(); int limit = 3000; @RequestMapping("/hello") public void hello() { counter.incr(); // 请求超过限制 if (counter.get() > limit) { // 限流 return; } try { // 业务逻辑 } finally { // 处理完毕, 数量减一 counter.decr(); } } }
创建一个计数器接口
public interface Counter { /** * increase 1 * @return */ int incr(); /** * decrease 1 * @return */ int decr(); /** * get current num * @return */ int get(); }
实现计数器接口
public class CounterBasic implements Counter { volatile int i = 0; // 本质是修改内存中某一个变量的值 public int incr() { // 字节码 // 1. 获取i的值 getfield #2 <com/tony/edu/juc/atomic/CounterBasic.i> int cuurent = i; // 2. 进行计算(+1) iadd int result = cuurent + 1; // 3. 赋值 putfield #2 <com/tony/edu/juc/atomic/CounterBasic.i> i = result; return result; } public int decr() { return i--; } @Override public int get() { return i; } }
测试计时器
public static void main(String[] args) throws InterruptedException { final Counter ct = new CounterBasic(); //模拟多线程场景 CountDownLatch countDownLatch = new CountDownLatch(2); for (int i = 0; i < 2; i++) { new Thread(() -> { long begin = System.nanoTime(); for (int j = 0; j < 10000; j++) { ct.incr(); } System.out.println("done...运算时间: " + (System.nanoTime() - begin)); countDownLatch.countDown(); }).start(); } countDownLatch.await(); System.out.println("计数器最终结果: " + ct.get()); // 预期结果应该 --- 20000 }
如果结果时正确的话,应该打印出 20000
打印结果,显示不是 两万
done...运算时间: 767900
done...运算时间: 387000
计数器最终结果: 19885
从结果可以发现, 该计数器并不能实现线程高并发安全