前言本文不是对RateLimiter的详细分析,只是一个总结分析。TokenBucketAlgorithm说到RateLimiter,就不得不说说令牌桶。其大致逻辑如下:照着图实现令牌桶图,网上随处可见,照着图实现也很简单。无非就是定时添加令牌桶,并提供一个获取令牌的函数,博主实现代码如下:5);publicstaticvoidmain(String[]args){MyRateLimitermyRateLimiter=newMyRateLimiter();myRateLimiter.addTokenFixedRate();for(inti=0;i<10;i++){myRateLimiter.acqurie();System.out.println("如何多次执行i:"+i+",执行时间为:"+System.currentTimeMillis());}}/***定时添加token*/publicvoidaddTokenFixedRate(){ScheduledExecutorServicescheduledExecutorService=Executors.newSingleThreadScheduledExecutor();scheduledExecutorService.scheduleAtFixedRate(()->{booleansuc=TOKEN_BUCKET.offer(1);if(!suc){System.out.println("令牌桶已满丢弃");}},0,200,TimeUnit.MILLISECONDS);}publicvoidacqurie(){while(TOKEN_BUCKET.poll()==null){};}}测试结果如下,基本满足RateLimiter汇总实现的要求。我先是按照自己实现的逻辑查看了Guava的RateLimiter的源码,发现RateLimiter并没有collection来充当bucket。核心是记录下一个token产生的时间和现有令牌的数量,并动态更新它们。大纲逻辑图如下:根据这个图看核心代码比较容易,摘录核心代码如下:;return1.0*microsToWait/SECONDS.toMicros(1L);}//Reserve一路往下找到如下代码byexistingtokensNumberofcardsdoublestoredPermitsToSpend=min(requiredPermits,this.storedPermits);//需要刷新的令牌数doublefreshPermits=requiredPermits-storedPermitsToSpend;//等待时间=需要刷新的令牌数*固定间隔+storagepermitwaitingtimelongwaitMicros=storedPermitsToWaitTime(this.storedPermits,storedPermitsToSpend)+(long)(freshPermits*stableIntervalMicros);//下一次token生产时间=本次token生产时间+等待时间this.nextFreeTicketMicros=LongMath.saturatedAdd(nextFreeTicketMicros,waitMicros);this.storedPermits-=storedPermitsToSpend;returnreturnValue;}总结:RateLimiter根本没有一个集合来充当桶。核心是记录下一个token产生的时间和已有token的数量,并动态更新。最后关注公众号Java技术栈,后台回复:面试,可以拿到我整理的Java系列面试题及答案,很全。
