多线程并发安全计数器实现限流(一) 简单实现

    面试题目:如何实现限流

    思路: 限制同一时间段的请求数量,即使用计数器来限制请求的数量。

               请求开始加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

 

从结果可以发现, 该计数器并不能实现线程高并发安全

 

posted @ 2020-09-06 14:58  抽象Java  阅读(475)  评论(0编辑  收藏  举报