优化注册中心心跳计数器
在之前的设计中,在增加心跳次数,获取心跳次数,以及重置心跳次数这几个方法都使用synchronized进行上锁。
优化之后,把心跳次数这个变量设置为AtomicLong类型,这样就可以避免,多线程串行化导致效率低的情况。
/**
*最近一分钟心跳次数
*/
private AtomicLong latestMinuteHeartbeatRate = new AtomicLong(0L);
/**
* 增加最近一分钟的心跳次数
*/
public void increment() {
//这种synchronized上锁,性能很差
//可能有很多线程,不断接收到心跳的请求,多个线程访问的时候都会卡在这个代码块上。
//就可以不用这个synchronized
//如果服务实例很多的话,1万个服务实例,每秒可能都有很多个请求过来更新心跳
//换成AtomicLong就可以,无锁话的cas操作,保证原子性,还可以多线程并发。
latestMinuteHeartbeatRate.incrementAndGet();
}
/**
* 获取最近一分钟的心跳次数
*/
public long get() {
return latestMinuteHeartbeatRate.get();
}
LongAddr解决cas自旋问题
我们知道cas存在一个问题,就是当大量多线程去并发的cas去操作一个变量的时候,某个线程就会不断的在doWhile循环中。导致cpu飙升。因此,jdk对这里做了一个优化,就是当多个线程来的时候,会搞多个cell,不同的线程操作不同的cell,这样就不会出现空轮询的一个操作。
当某一个线程如果对一个Cell更新的时候,发现说出现了很难更新他的值,出现了多次自旋的一个问题,如果他CAS失败了,自动迁移段,他会去尝试更新别的Cell的值,这样的话就可以让一个线程不会盲目的等待一个cell的值。
同时当获取值的时候,时会把base和所有cell累加起来去做值返回,因为一开始的时候线程不多时还是在base上操作的。
LongAdder优化心跳计数器效率
讲AtomicLong换成LongAdder即可
/**
*最近一分钟心跳次数
*/
// private AtomicLong latestMinuteHeartbeatRate = new AtomicLong(0L);
private LongAdder latestMinuteHeartbeatRate = new LongAdder();