我有一个库,可以对我的服务进行HTTP调用。我试图计算我的服务平均花费的平均运行平均值。
以下是我如何计算"运行平均值"。
的核心逻辑import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.LinkedList;
import java.util.Queue;
public class MovingAverage {
private final Queue<BigDecimal> window = new ArrayDeque<BigDecimal>();
private final int period;
private BigDecimal sum = BigDecimal.ZERO;
public MovingAverage(int period) {
this.period = period;
}
public void add(BigDecimal num) {
sum = sum.add(num);
window.add(num);
if (window.size() > period) {
sum = sum.subtract(window.remove());
}
}
public BigDecimal getAverage() {
if (window.isEmpty()) return BigDecimal.ZERO;
BigDecimal divisor = BigDecimal.valueOf(window.size());
return sum.divide(divisor, 2, RoundingMode.HALF_UP);
}
}
此代码线程是否安全,因为这是从多线程程序调用的?如果不是,我怎么能做这个多线程。
我想确保此运行平均计算速度很快,因为此库在非常繁重的负载下运行,因此这不会增加整体延迟。另外我怀疑我甚至需要在这里使用BigDecimal
,double
或long
可能会在这里使用。
答案 0 :(得分:1)
这段代码不是线程安全的,想象下一个序列:
initial state: MovingAverage queue is empty
thread 1: calls add(1), sum is 1, window size is 1
thread 2: calls add(1), pauses after sum = sum.add(num), sum is 2, window size is 1
thread 1: calls getAverage, it will return 2/1 = 2
另一个用例:
thread 1: calls add(1), pauses after sum.add(num), but before sum =
thread 2: calls add(1), sets sum to 1
thread 1: continues, overwrites sum with 1, but should be 2, as windows size is updated to 2
使其安全的最简单方法 - 在每个方法之前添加synchronized
,但会降低执行速度
答案 1 :(得分:0)
为什么不使用 http://mvnrepository.com/artifact/com.codahale.metrics? 然后创建度量标准注册表,并使用例如直方图。它会给你平均值和更多(p99,p999)
MetricRegistry metricRegistry = new MetricRegistry();
Histogram histogram = metricRegistry.histogram("stats");
然后在代码中:
histogram.update(operationTimeInMilliseconds)