滑动窗口计数有很多使用场景,比如说限流防止系统雪崩。相比计数实现,滑动窗口实现会更加平滑,能自动消除毛刺。

概念上可以参考TCP的滑窗算法,可以看一下这篇文章(http://go12345.iteye.com/blog/1744728)。在实现上,滑动窗口算法需要循环队列和线程安全保障。

下面的实现有几个点

1, 支持滑窗大小运行时动态调整

2, 基于 java8 编译器

3, DEMO实现只支持一个窗口对象,如果要支持多个,需要修改 SlotBaseCounter 类

  1. package slidingwindow;
  2. import java.util.Arrays;
  3. import java.util.concurrent.atomic.AtomicInteger;
  4. /**
  5. * Created by admin on 2016/02/20.
  6. */
  7. public class SlotBaseCounter {
  8. private int slotSize;
  9. private AtomicInteger[] slotCounter;
  10. public SlotBaseCounter(int slotSize) {
  11. slotSize = slotSize < 1 ? 1 : slotSize;
  12. this.slotSize = slotSize;
  13. this.slotCounter = new AtomicInteger[slotSize];
  14. for (int i = 0; i < this.slotSize; i++) {
  15. slotCounter[i] = new AtomicInteger(0);
  16. }
  17. }
  18. public void increaseSlot(int slotSize) {
  19. slotCounter[slotSize].incrementAndGet();
  20. }
  21. public void wipeSlot(int slotSize) {
  22. slotCounter[slotSize].set(0);
  23. }
  24. public int totalCount() {
  25. return Arrays.stream(slotCounter).mapToInt(slotCounter -> slotCounter.get()).sum();
  26. }
  27. @Override
  28. public String toString() {
  29. return Arrays.toString(slotCounter);
  30. }
  31. }
  1. package slidingwindow;
  2. /**
  3. * Created by admin on 2016/02/20.
  4. */
  5. public class SlidingWindowCounter {
  6. private volatile SlotBaseCounter slotBaseCounter;
  7. private volatile int windowSize;
  8. private volatile int head;
  9. public SlidingWindowCounter(int windowSize) {
  10. resizeWindow(windowSize);
  11. }
  12. public synchronized void resizeWindow(int windowSize) {
  13. this.windowSize = windowSize;
  14. this.slotBaseCounter = new SlotBaseCounter(windowSize);
  15. this.head = 0;
  16. }
  17. public void increase() {
  18. slotBaseCounter.increaseSlot(head);
  19. }
  20. public int totalAndAdvance() {
  21. int total = totalCount();
  22. advance();
  23. return total;
  24. }
  25. public void advance() {
  26. int tail = (head + 1) % windowSize;
  27. slotBaseCounter.wipeSlot(tail);
  28. head = tail;
  29. }
  30. public int totalCount() {
  31. return slotBaseCounter.totalCount();
  32. }
  33. @Override
  34. public String toString() {
  35. return "total = " + totalCount() + " head = " + head + " >> " + slotBaseCounter;
  36. }
  37. }
  1. package slidingwindow;
  2. import java.util.concurrent.TimeUnit;
  3. /**
  4. * Created by admin on 2016/02/20.
  5. */
  6. public class Loops {
  7. public static void dieLoop(Runnable runnable) {
  8. while (true) {
  9. run(runnable);
  10. }
  11. }
  12. public static void rateLoop(Runnable runnable, int mills) {
  13. while (true) {
  14. try {
  15. TimeUnit.MILLISECONDS.sleep(mills);
  16. } catch (InterruptedException e) {
  17. }
  18. run(runnable);
  19. }
  20. }
  21. public static void fixLoop(Runnable runnable, int loop) {
  22. for (int i = 0; i < loop; i++) {
  23. run(runnable);
  24. }
  25. }
  26. private static void run(Runnable runnable) {
  27. try {
  28. runnable.run();
  29. } catch (Exception e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }
  1. package slidingwindow;
  2. import org.junit.Test;
  3. import java.io.IOException;
  4. import java.util.Random;
  5. import java.util.Scanner;
  6. import java.util.concurrent.ExecutorService;
  7. import java.util.concurrent.Executors;
  8. import java.util.concurrent.ScheduledExecutorService;
  9. import java.util.concurrent.TimeUnit;
  10. /**
  11. * Created by admin on 2016/02/20.
  12. */
  13. public class SlidingWindowCounterTest {
  14. private ExecutorService es = Executors.newCachedThreadPool();
  15. private ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
  16. @Test
  17. public void testNWindow() throws IOException {
  18. SlidingWindowCounter swc = new SlidingWindowCounter(3);
  19. ses.scheduleAtFixedRate(() -> {
  20. Loops.fixLoop(swc::increase, new Random().nextInt(10));
  21. }, 10, 2, TimeUnit.MILLISECONDS);
  22. ses.scheduleAtFixedRate(() -> {
  23. System.out.println(swc);
  24. swc.advance();
  25. }, 1, 1, TimeUnit.SECONDS);
  26. ses.scheduleAtFixedRate(() -> {
  27. swc.resizeWindow(new Random().nextInt(10));
  28. }, 1, 10, TimeUnit.SECONDS);
  29. System.in.read();
  30. }
  31. @Test
  32. public void test1Window() {
  33. SlidingWindowCounter swc = new SlidingWindowCounter(1);
  34. System.out.println(swc);
  35. swc.increase();
  36. swc.increase();
  37. System.out.println(swc);
  38. swc.advance();
  39. System.out.println(swc);
  40. swc.increase();
  41. swc.increase();
  42. System.out.println(swc);
  43. }
  44. @Test
  45. public void test3Window() {
  46. SlidingWindowCounter swc = new SlidingWindowCounter(3);
  47. System.out.println(swc);
  48. swc.increase();
  49. System.out.println(swc);
  50. swc.advance();
  51. System.out.println(swc);
  52. swc.increase();
  53. swc.increase();
  54. System.out.println(swc);
  55. swc.advance();
  56. System.out.println(swc);
  57. swc.increase();
  58. swc.increase();
  59. swc.increase();
  60. System.out.println(swc);
  61. swc.advance();
  62. System.out.println(swc);
  63. swc.increase();
  64. swc.increase();
  65. swc.increase();
  66. swc.increase();
  67. System.out.println(swc);
  68. swc.advance();
  69. System.out.println(swc);
  70. }
  71. }

这是部分测试结果输出:

total = 2245 head = 0 >> [2245, 0, 0, 0, 0, 0]

total = 4561 head = 1 >> [2245, 2316, 0, 0, 0, 0]

total = 6840 head = 2 >> [2245, 2316, 2279, 0, 0, 0]

total = 8994 head = 3 >> [2245, 2316, 2279, 2154, 0, 0]

total = 11219 head = 4 >> [2245, 2316, 2279, 2154, 2225, 0]

total = 13508 head = 5 >> [2245, 2316, 2279, 2154, 2225, 2289]

total = 13602 head = 0 >> [2339, 2316, 2279, 2154, 2225, 2289]

total = 13465 head = 1 >> [2339, 2179, 2279, 2154, 2225, 2289]

total = 13474 head = 2 >> [2339, 2179, 2288, 2154, 2225, 2289]

total = 13551 head = 3 >> [2339, 2179, 2288, 2231, 2225, 2289]

total = 2192 head = 0 >> [2192]

total = 2207 head = 0 >> [2207]

total = 2291 head = 0 >> [2291]

total = 2257 head = 0 >> [2257]

total = 2250 head = 0 >> [2250]

total = 2201 head = 0 >> [2201]

total = 2299 head = 0 >> [2299]

total = 2223 head = 0 >> [2223]

total = 2190 head = 0 >> [2190]

total = 2306 head = 0 >> [2306]

total = 2290 head = 0 >> [2290, 0, 0, 0, 0, 0, 0, 0, 0]

total = 4474 head = 1 >> [2290, 2184, 0, 0, 0, 0, 0, 0, 0]

total = 6632 head = 2 >> [2290, 2184, 2158, 0, 0, 0, 0, 0, 0]

total = 8744 head = 3 >> [2290, 2184, 2158, 2112, 0, 0, 0, 0, 0]

total = 11008 head = 4 >> [2290, 2184, 2158, 2112, 2264, 0, 0, 0, 0]

total = 13277 head = 5 >> [2290, 2184, 2158, 2112, 2264, 2269, 0, 0, 0]

total = 15446 head = 6 >> [2290, 2184, 2158, 2112, 2264, 2269, 2169, 0, 0]

total = 17617 head = 7 >> [2290, 2184, 2158, 2112, 2264, 2269, 2169, 2171, 0]

total = 19749 head = 8 >> [2290, 2184, 2158, 2112, 2264, 2269, 2169, 2171, 2132]

total = 19608 head = 0 >> [2149, 2184, 2158, 2112, 2264, 2269, 2169, 2171, 2132]

total = 2256 head = 0 >> [2256, 0, 0, 0]

total = 4624 head = 1 >> [2256, 2368, 0, 0]

total = 6811 head = 2 >> [2256, 2368, 2187, 0]

total = 8973 head = 3 >> [2256, 2368, 2187, 2162]

total = 8934 head = 0 >> [2217, 2368, 2187, 2162]

total = 8798 head = 1 >> [2217, 2232, 2187, 2162]

total = 8912 head = 2 >> [2217, 2232, 2301, 2162]

total = 8940 head = 3 >> [2217, 2232, 2301, 2190]

total = 8987 head = 0 >> [2264, 2232, 2301, 2190]

total = 9049 head = 1 >> [2264, 2294, 2301, 2190]

total = 2220 head = 0 >> [2220, 0, 0, 0, 0, 0, 0]

total = 4477 head = 1 >> [2220, 2257, 0, 0, 0, 0, 0]

total = 6718 head = 2 >> [2220, 2257, 2241, 0, 0, 0, 0]

total = 8939 head = 3 >> [2220, 2257, 2241, 2221, 0, 0, 0]

total = 11174 head = 4 >> [2220, 2257, 2241, 2221, 2235, 0, 0]

total = 13420 head = 5 >> [2220, 2257, 2241, 2221, 2235, 2246, 0]

total = 15673 head = 6 >> [2220, 2257, 2241, 2221, 2235, 2246, 2253]

total = 15779 head = 0 >> [2326, 2257, 2241, 2221, 2235, 2246, 2253]

total = 15796 head = 1 >> [2326, 2274, 2241, 2221, 2235, 2246, 2253]

total = 15802 head = 2 >> [2326, 2274, 2247, 2221, 2235, 2246, 2253]

滑动窗口计数java实现的更多相关文章

  1. Storm 实现滑动窗口计数和TopN排序

    计算top N words的topology, 用于比如trending topics or trending images on Twitter. 实现了滑动窗口计数和TopN排序, 比较有意思,  ...

  2. 【Java】 剑指offer(59-1) 滑动窗口的最大值

      本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 给定一个数组和滑动窗口的大小,请找出所有滑动窗口里的最大值.例 ...

  3. Leetcode 239题 滑动窗口最大值(Sliding Window Maximum) Java语言求解

    题目链接 https://leetcode-cn.com/problems/sliding-window-maximum/ 题目内容 给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧 ...

  4. Java实现 LeetCode 480 滑动窗口中位数

    480. 滑动窗口中位数 中位数是有序序列最中间的那个数.如果序列的大小是偶数,则没有最中间的数:此时中位数是最中间的两个数的平均数. 例如: [2,3,4],中位数是 3 [2,3],中位数是 (2 ...

  5. Java实现 LeetCode 239 滑动窗口最大值

    239. 滑动窗口最大值 给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以看到在滑动窗口内的 k 个数字.滑动窗口每次只向右移动一位. 返回滑动窗口中的最 ...

  6. Sentinel源码分析-滑动窗口统计原理

    滑动窗口技术是Sentinel比较关键的核心技术,主要用于数据统计 通过分析StatisticSlot来慢慢引出这个概念 @Override public void entry(Context con ...

  7. uva 1606 amphiphilic carbon molecules【把缩写写出来,有惊喜】(滑动窗口)——yhx

    Shanghai Hypercomputers, the world's largest computer chip manufacturer, has invented a new classof ...

  8. hdu-5497 Inversion(滑动窗口+树状数组)

    题目链接: Inversion Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)T ...

  9. storm 1.0版本滑动窗口的实现及原理

    滑动窗口在监控和统计应用的场景比较广泛,比如每隔一段时间(10s)统计最近30s的请求量或者异常次数,根据请求或者异常次数采取相应措施.在storm1.0版本之前,没有提供关于滑动窗口的实现,需要开发 ...

随机推荐

  1. 国内 docker 仓库镜像对比

    http://www.datastart.cn/tech/2016/09/28/docker-mirror.html

  2. cocurrent包 原子性数据类型

    22. 原子性布尔 AtomicBoolean AtomicBoolean 类为我们提供了一个可以用原子方式进行读和写的布尔值,它还拥有一些先进的原子性操作,比如 compareAndSet().At ...

  3. java amr格式转mp3格式(完美解决Linux下转换0K问题)

    原文:http://linjie.org/2015/08/06/amr%E6%A0%BC%E5%BC%8F%E8%BD%ACmp3%E6%A0%BC%E5%BC%8F-%E5%AE%8C%E7%BE% ...

  4. DELPHI的一些开源项目GIT地址

    DELPHI的一些开源项目GIT地址 Delphi-Cross-Sockethttps://github.com/winddriver/Delphi-Cross-Socket 跨平台的SOCKET库 ...

  5. How to create an IPA (Xcode 5)

    This tutorial will walk you through the easiest way to generate an IPA using Xcode 5. We will be usi ...

  6. JAVA常见算法题(八)

    package com.xiaowu.demo; /** * 求s=a+aa+aaa+aaaa+aa...a的值,其中a是一个数字.例如2+22+222+2222+22222(此时共有5个数相加), ...

  7. windows下搭建svn服务器

    转自:http://www.cnblogs.com/cloud2rain/archive/2013/04/11/3015080.html 这篇文档非常好,转来学习,有一点就是把subversion创建 ...

  8. Linux内核实践之工作队列

    工作队列(work queue)是另外一种将工作推后执行的形式,它和tasklet有所不同.工作队列可以把工作推后,交由一个内核线程去执行,也就是说,这个下半部分可以在进程上下文中执行.这样,通过工作 ...

  9. ElasticSearch 相关性

    1.相关性 ElasticSearch检索结果是按照相关性倒序排列的,相关性是什么,相关性又是如何计算的?每个文档都有相关性评分,用一个正浮点数字段 _score 来表示 . _score 的评分越高 ...

  10. 转: 苹果APNS的说明

    转: http://toutiao.com/a6276578687162040578/?tt_from=weixin&utm_campaign=client_share&app=new ...