我有客户端 - 服务器应用程序,我需要测量每秒请求到达率(请求率)。为此,我有一个计时器对象,每秒后激活,读取同步计数器,然后将其设置为零。计数器在每个请求到达时递增。我使用以下代码来检测请求率。在我的应用程序中运行有很多其他线程和计时器。问题是"由于计时器的不准确性,我没有得到完美的请求率"。除了使用计时器之外,还有其他测量请求率的方法。
public class FrequencyDetector extends TimerTask {
RequestCounter requestCounter;
FrequencyHolder frequencyHolder;
public FrequencyDetector(RequestCounter requestCounter,FrequencyHolder frequencyHolder){
this.frequencyHolder=new FrequencyHolder();
this.frequencyHolder=frequencyHolder;
}
@Override
public void run() {
int newFrequency=requestCounter.getCounter();
frequencyHolder.setFrequency(newFrequency);
requestCounter.setCounterToZero();
//calls to other fuctions
}
}
答案 0 :(得分:0)
您可以检查每单位计时器的时间,而不是每单位时间检查计数器。这可能会给你更准确的结果。算法如下。
FIXED_LIMIT
frequency=FIXED_LIMIT/duration since last record
计算频率时
然而,这将以不可预测的间隔记录频率,如果请求频率减少,则连续记录之间的持续时间将增加。
为了处理它我们可以实现自适应算法,下面给出算法。
ADAPTIVE_LIMIT
记录频率时
frequency=ADAPTIVE_LIMIT/duration since last record
以上算法将根据上次记录的频率重置限制。它被认为不会以最佳间隔录制,但它会非常接近。
此外,它还可以为您提供高度准确的频率,因为它不依赖于任何预定的线程。
以下是这种自适应计数器的实现。
ADAPTIVE_LIMIT=frequency * DESIRED RECORD INTERVAL
<强>输出强>
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
public class TestCounter {
//Keep initial counterInterval to a small value otherwise first record may take long time
final AtomicLong counterInterval = new AtomicLong(10);
AtomicLong requestCounter = new AtomicLong();
volatile long lastTime;
/**OPTIMAL_DURATION is the duration after which frequency is expected to be recorded
* Program adaptively tries to reach this duration
*/
static final double OPTIMAL_DURATION = 1.0; // 1 second
static final Random random = new Random();
public static void main(String[] args) {
System.out.println("Started ");
TestCounter main = new TestCounter();
for(int i = 0; i < 1000; i++) {
main.requestArrived();
}
}
/*
* Simulating requests
*/
public void requestArrived() {
printCounter();
try {
Thread.sleep(random.nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//This will be in some Utility class
private void printCounter() {
requestCounter.incrementAndGet();
long currentTime = System.nanoTime();
long currentInterval = counterInterval.get();
if(requestCounter.get() > currentInterval) {
if(lastTime != 0) {
long timeDelta = currentTime - lastTime;
long frequency = (long)(currentInterval / (timeDelta / 1e9));
System.out.printf("time=%.2f, frequency=%d\n", (timeDelta / 1e9), frequency);
//updating the currentInterval for the miss
long newCounterInterval = (long)(frequency * OPTIMAL_DURATION);
counterInterval.set(newCounterInterval);
}
requestCounter.set(0);
lastTime = currentTime;
}
}
}