固定窗口计数器算法Java实现

Java Implementation of Fixed Window Counter Algorithm

实现

import java.time.Instant; import java.time.ZoneId; import java.time.temporal.ChronoUnit; /** * 固定窗口计数器,使用固定窗口计数器算法进行限流 * * @author qzy * */ public class FixedWindowCounter { private static final ZoneId SYSTEM_DEFAULT_ZONE = ZoneId.systemDefault();// 系统默认时区 private double limit;// 单个窗口内的配额限制 private long windowDuration;// 窗口大小 private ChronoUnit windowDurationUnit;// 窗口大小的单位(ms、s、m、h) private double count;// 当前窗口内的已用配额 private long nextWindowStart;// 下一个窗口的起始时间戳 /** * @param limit 单个窗口内的配额限制 * @param windowDuration 窗口大小 * @param windowDurationUnit 窗口大小的单位(ms、s、m、h) */ public FixedWindowCounter(double limit, long windowDuration, ChronoUnit windowDurationUnit) { this.limit = limit; this.windowDuration = windowDuration; this.windowDurationUnit = windowDurationUnit; } /** * 请求配额 * * @param number 所需配额 * @return true表示请求成功,false表示请求失败 */ public synchronized boolean acquire(double number) { long now = System.currentTimeMillis(); if (now >= nextWindowStart) {// 进入了下一个窗口 count = 0;// 将计数器归零 nextWindowStart = calculateNextWindowStart(now);// 计算下一个窗口的起始时间戳 } if (number > limit - count) {// 配额不够用 return false; } count += number;// 记录已用配额 return true; } /** * 计算下一个窗口的起始时间戳 * * @param now * @return */ private long calculateNextWindowStart(long now) { ChronoUnit truncatedToUnit; switch (windowDurationUnit) { case MILLIS: truncatedToUnit = ChronoUnit.SECONDS; break; case SECONDS: truncatedToUnit = ChronoUnit.MINUTES; break; case MINUTES: truncatedToUnit = ChronoUnit.HOURS; break; case HOURS: truncatedToUnit = ChronoUnit.DAYS; break; default: throw new RuntimeException("不支持的时间窗口大小"); } Instant nowInstant = Instant.ofEpochMilli(now); Instant start = nowInstant.atZone(SYSTEM_DEFAULT_ZONE).truncatedTo(truncatedToUnit).toInstant(); while (!start.isAfter(nowInstant)) {// 如果窗口起始时间不在当前时间之后 start = start.plus(windowDuration, windowDurationUnit);// 向后移动一个窗口 } return start.toEpochMilli(); } }

测试

import java.time.temporal.ChronoUnit; public class Test { public static void main(String[] args) { FixedWindowCounter fixedWindowCounter = new FixedWindowCounter(7, 10, ChronoUnit.SECONDS); long totalCount = 0, successCount = 0; while (true) { totalCount++; if (fixedWindowCounter.acquire(1)) { successCount++; System.out.printf("%s\t%s\t%s\n", System.currentTimeMillis(), successCount, totalCount); } } } }

 

 

文章评论
${fromAuthor ? '郄正元' : '游客'} 作者 ${gmtCreate}
${content}
${subList.length}
发表评论
${commentToArticle ? '' : parentContent}
字数:0/${maxCommentLength}
该邮箱地址仅用于接收其他用户的回复提醒,不会泄露