You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java:高效10秒平均性能计数器的可靠重置方案求助

可靠低开销的10秒窗口操作计数方案

问题分析

  • 原模10数组方案的缺陷:依赖操作触发模值切换来重置桶,当某一秒无操作时,对应桶的旧值会残留,导致后续统计错误
  • 定时任务方案的缺陷:无法保证精准执行,受系统负载、时钟偏差影响可能跳秒,仍会出现重置遗漏
  • 核心需求:低开销(支持25k ops/s)、准确统计过去10秒操作数、无需依赖不可靠的定时任务

解决方案:时间戳标记的桶数组

核心思路是给每个桶添加时间戳标记,每次计数触发时主动清理过期桶,不再依赖模值切换或定时任务。具体实现如下:

代码实现

private static class Bucket {
    long windowStart; // 桶对应的1秒窗口起始毫秒数(如1700000000000)
    int count;
}

private final Bucket[] buckets = new Bucket[10];
private final Object lock = new Object();

// 初始化桶
public Counter() {
    for (int i = 0; i < buckets.length; i++) {
        buckets[i] = new Bucket();
        buckets[i].windowStart = 0;
        buckets[i].count = 0;
    }
}

public void notifyCountX() {
    long now = System.currentTimeMillis();
    // 计算当前1秒窗口的起始时间
    long currentWindow = now - (now % 1000);
    int currentIndex = (int) (currentWindow / 1000 % 10);

    synchronized (lock) {
        // 清理所有过期桶(时间早于当前时间-10秒)
        long cutoff = now - 10000;
        for (Bucket bucket : buckets) {
            if (bucket.windowStart < cutoff) {
                bucket.count = 0;
                bucket.windowStart = 0; // 标记为已过期
            }
        }

        // 更新当前桶计数
        Bucket currentBucket = buckets[currentIndex];
        if (currentBucket.windowStart != currentWindow) {
            // 当前桶未对应当前窗口,重置计数
            currentBucket.count = 1;
            currentBucket.windowStart = currentWindow;
        } else {
            currentBucket.count += 1;
        }
    }
}

// 获取过去10秒的平均operations/s
public double getOperationsPerSecond() {
    synchronized (lock) {
        long now = System.currentTimeMillis();
        long cutoff = now - 10000;
        int total = 0;
        for (Bucket bucket : buckets) {
            if (bucket.windowStart >= cutoff) {
                total += bucket.count;
            }
        }
        return total / 10.0;
    }
}

方案优势

  • 低开销:每次操作仅需遍历10个桶,相对于25k ops/s的吞吐量,该开销可忽略不计,远低于存储每个操作时间戳的方案
  • 可靠重置:每次计数时主动检查并清理过期桶,无论是否有连续操作,都不会残留旧计数
  • 无定时依赖:完全由计数触发清理逻辑,避免了定时任务的精度问题
  • 线程安全:通过同步锁保证多线程环境下的计数准确性

关键细节说明

  • 用System.currentTimeMillis()替代过时的Date.getSeconds(),获取时间更高效准确
  • 每个桶存储对应1秒窗口的起始时间,确保同一秒内的操作归到同一个桶
  • 清理逻辑以当前时间-10秒为阈值,严格保证统计范围是过去10秒的操作

内容的提问来源于stack exchange,提问作者dognose

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 14:15:07