我最近开始学习 CodaHale/DropWizard 指标库。我无法理解 Meter 类是如何线程安全的(根据文档),尤其是 mark() 和 tickIfNecessary() 方法:
public void mark(long n) {
tickIfNecessary();
count.add(n);
m1Rate.update(n);
m5Rate.update(n);
m15Rate.update(n);
}
private void tickIfNecessary() {
final long oldTick = lastTick.get();
final long newTick = clock.getTick();
final long age = newTick - oldTick;
if (age > TICK_INTERVAL) {
final long newIntervalStartTick = newTick - age % TICK_INTERVAL;
if (lastTick.compareAndSet(oldTick, newIntervalStartTick)) {
final long requiredTicks = age / TICK_INTERVAL;
for (long i = 0; i < requiredTicks; i++) {
m1Rate.tick();
m5Rate.tick();
m15Rate.tick();
}
}
}
}
我可以看到有一个 AtomicLong 类型的 lastTick,但仍然可能存在 m1-m15 速率滴答声稍长一点的情况,因此另一个线程可以调用这些滴答声以及下一个 TICK_INTERVAL 的一部分。由于 Rates 的 tick() 方法根本不同步,这难道不是一种竞争条件吗?https://github.com/dropwizard/metrics/blob/3.2-development/metrics-core/src/main/java/com/codahale/metrics/EWMA.java#L86-L95
public void tick() {
final long count = uncounted.sumThenReset();
final double instantRate = count / interval;
if (initialized) {
rate += (alpha * (instantRate - rate));
} else {
rate = instantRate;
initialized = true;
}
}
谢谢,
玛丽安