guava 16版本中的WarmingUp 的许可,即storedPermits是字段,是非常关键的属性,它会随时间推移不断的变化,我们怎么样即使的动态观察它呢? 因为它是私有字段,而且是惰性的,因为因为RateLimiter 允许提前消费,这意味着它确实比较难观察。 我想到了下面的方法:
public void testSmoothwarmingUp() throws Exception { RateLimiter r = RateLimiter.create(2, 3, TimeUnit.SECONDS); Class<RateLimiter> rateLimiterClass = RateLimiter.class; Field storedPermits = rateLimiterClass.getDeclaredField("storedPermits");// 必须要getDeclaredField, 不能getField storedPermits.setAccessible(true); ReflectionUtils.makeAccessible(storedPermits); Object o = storedPermits.get(r); System.out.println(o + " get 1 tokens: ++++++++ " + 000000); try { Thread.sleep(3000); } catch (Exception e) { e.printStackTrace(); } while (true) { o = storedPermits.get(r); System.out.println(o + " get 1 tokens: " + r.acquire(3) + "s");// 前3个permets耗时warmupPeriod, o = storedPermits.get(r); System.out.println(o + " get 1 tokens: " + r.acquire(1) + "s"); o = storedPermits.get(r); System.out.println(o + " get 1 tokens: " + r.acquire(1) + "s");// 第四个permets之后 速率已经达到最高,完全稳定。 o = storedPermits.get(r); System.out.println(o + " get 1 tokens: " + r.acquire(1) + "s"); o = storedPermits.get(r); System.out.println("o = " + o); /** * output: * get 1 tokens: 0.0s * get 1 tokens: 1.329289s * get 1 tokens: 0.994375s * get 1 tokens: 0.662888s 上边三次获取的时间相加正好为3秒 * end * get 1 tokens: 0.49764s 正常速率0.5秒一个令牌 * get 1 tokens: 0.497828s * get 1 tokens: 0.49449s * get 1 tokens: 0.497522s */ System.out.println(o + " get 1 tokens: " + r.acquire(3) + "s"); try { int millis = 4000; // 不管之前是什么情况,不管之前acquire多少, 这里只要sleep超过warmupPeriod时间, 就会完全冷却 // xxx 错错错 // 不管之前是什么情况,只要上一个acquire小于maxPermits - thresholdPermits, 这里只要sleep超过warmupPeriod时间, 就会完全冷却 Thread.sleep(millis); // sleep warmupPeriod + extra时间, 可以保证完全冷却;extra时间是指 // Thread.sleep(millis); // 债务还清之后(即过了extra时间之后),再sleep warmupPeriod/2 时间,将处于临界点:storedPermits = thresholdPermits System.out.println("sleep " + millis); } catch (InterruptedException e) { e.printStackTrace(); } // boolean b = r.tryAcquire(6); r.setRate(r.getRate());// 通过此方法触发resync方法,进而可以设置storedPermits字段的值为最新值 o = storedPermits.get(r);// 当限流器经过warmupPeriod时间之后,它就会完全冷却,不过此时 无法观察到storedPermits字段,因为它是惰性的 System.out.println(o + " get 1 tokens: " + r.acquire(1) + "s"); o = storedPermits.get(r); System.out.println(o + " get 1 tokens: " + r.acquire(2) + "s"); o = storedPermits.get(r); System.out.println(o + " get 1 tokens: " + r.acquire(3) + "s"); o = storedPermits.get(r); System.out.println(o + " get 1 tokens: " + r.acquire(1) + "s"); o = storedPermits.get(r); System.out.println(o + " get 1 tokens: " + r.acquire(1) + "s"); o = storedPermits.get(r); System.out.println(o + " get 3 tokens: " + r.acquire(3) + "s"); System.out.println("end"); }
这样之后,测试、观察就方便多了!!