优化注册中心心跳计数器

在之前的设计中,在增加心跳次数,获取心跳次数,以及重置心跳次数这几个方法都使用synchronized进行上锁。
优化之后,把心跳次数这个变量设置为AtomicLong类型,这样就可以避免,多线程串行化导致效率低的情况。

  1. /**
  2. *最近一分钟心跳次数
  3. */
  4. private AtomicLong latestMinuteHeartbeatRate = new AtomicLong(0L);
  5. /**
  6. * 增加最近一分钟的心跳次数
  7. */
  8. public void increment() {
  9. //这种synchronized上锁,性能很差
  10. //可能有很多线程,不断接收到心跳的请求,多个线程访问的时候都会卡在这个代码块上。
  11. //就可以不用这个synchronized
  12. //如果服务实例很多的话,1万个服务实例,每秒可能都有很多个请求过来更新心跳
  13. //换成AtomicLong就可以,无锁话的cas操作,保证原子性,还可以多线程并发。
  14. latestMinuteHeartbeatRate.incrementAndGet();
  15. }
  16. /**
  17. * 获取最近一分钟的心跳次数
  18. */
  19. public long get() {
  20. return latestMinuteHeartbeatRate.get();
  21. }

LongAddr解决cas自旋问题

我们知道cas存在一个问题,就是当大量多线程去并发的cas去操作一个变量的时候,某个线程就会不断的在doWhile循环中。导致cpu飙升。因此,jdk对这里做了一个优化,就是当多个线程来的时候,会搞多个cell,不同的线程操作不同的cell,这样就不会出现空轮询的一个操作。
当某一个线程如果对一个Cell更新的时候,发现说出现了很难更新他的值,出现了多次自旋的一个问题,如果他CAS失败了,自动迁移段,他会去尝试更新别的Cell的值,这样的话就可以让一个线程不会盲目的等待一个cell的值。
同时当获取值的时候,时会把base和所有cell累加起来去做值返回,因为一开始的时候线程不多时还是在base上操作的。
image.png

LongAdder优化心跳计数器效率

讲AtomicLong换成LongAdder即可

  1. /**
  2. *最近一分钟心跳次数
  3. */
  4. // private AtomicLong latestMinuteHeartbeatRate = new AtomicLong(0L);
  5. private LongAdder latestMinuteHeartbeatRate = new LongAdder();