TimeMetric.java 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /**
  2. * DBSyncer Copyright 2020-2024 All Rights Reserved.
  3. */
  4. package org.dbsyncer.common.metric;
  5. import java.util.concurrent.locks.ReentrantLock;
  6. /**
  7. * @Author AE86
  8. * @Version 1.0.0
  9. * @Date 2024-06-02 22:44
  10. */
  11. public class TimeMetric {
  12. /**
  13. * 槽位的数量
  14. */
  15. private int bucketSize;
  16. /**
  17. * 时间片,单位毫秒
  18. */
  19. private int slice;
  20. /**
  21. * 用于判断是否可跳过锁争抢
  22. */
  23. private int timeSliceUsed;
  24. /**
  25. * 槽位
  26. */
  27. private Bucket[] buckets;
  28. /**
  29. * 目标槽位的位置
  30. */
  31. private volatile Integer targetBucketPosition;
  32. /**
  33. * 接近目标槽位最新时间
  34. */
  35. private volatile Long latestPassedTime;
  36. /**
  37. * 进入下一个槽位时使用的锁
  38. */
  39. private ReentrantLock enterNextBucketLock;
  40. /**
  41. * 默认60个槽位,槽位的时间片为1000毫秒
  42. */
  43. public TimeMetric() {
  44. this(60, 1000);
  45. }
  46. /**
  47. * 初始化Bucket数量与每个Bucket的时间片
  48. *
  49. * @param bucketSize
  50. * @param slice
  51. */
  52. public TimeMetric(int bucketSize, int slice) {
  53. this.bucketSize = bucketSize;
  54. this.slice = slice;
  55. this.latestPassedTime = System.currentTimeMillis() - (2 * slice);
  56. this.timeSliceUsed = 3 * slice;
  57. this.targetBucketPosition = getTargetBucketPosition(System.currentTimeMillis());
  58. this.enterNextBucketLock = new ReentrantLock();
  59. this.buckets = new Bucket[bucketSize];
  60. for (int i = 0; i < bucketSize; i++) {
  61. this.buckets[i] = new Bucket();
  62. }
  63. }
  64. public void add(long count) {
  65. long passTime = System.currentTimeMillis();
  66. Bucket currentBucket = buckets[targetBucketPosition];
  67. if (passTime - latestPassedTime < slice) {
  68. currentBucket.add(count);
  69. return;
  70. }
  71. if (enterNextBucketLock.isLocked() && passTime - latestPassedTime < timeSliceUsed) {
  72. currentBucket.add(count);
  73. return;
  74. }
  75. try {
  76. enterNextBucketLock.lock();
  77. if (passTime - latestPassedTime < slice) {
  78. currentBucket.add(count);
  79. return;
  80. }
  81. int nextTargetBucketPosition = getTargetBucketPosition(passTime);
  82. Bucket nextBucket = buckets[nextTargetBucketPosition];
  83. if (nextBucket.equals(currentBucket)) {
  84. if (passTime - latestPassedTime >= slice) {
  85. latestPassedTime = passTime;
  86. }
  87. } else {
  88. nextBucket.reset();
  89. targetBucketPosition = nextTargetBucketPosition;
  90. latestPassedTime = passTime;
  91. }
  92. nextBucket.add(count);
  93. } finally {
  94. enterNextBucketLock.unlock();
  95. }
  96. }
  97. public long getSecondsRate() {
  98. return System.currentTimeMillis() - latestPassedTime < slice ? buckets[targetBucketPosition].get() : 0L;
  99. }
  100. private Integer getTargetBucketPosition(long now) {
  101. return (int) (now / slice) % bucketSize;
  102. }
  103. }