SequenceGenUtil.java 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package com.zsElectric.boot.common.util;
  2. import lombok.Getter;
  3. import java.time.LocalDateTime;
  4. import java.time.format.DateTimeFormatter;
  5. import java.util.concurrent.atomic.AtomicInteger;
  6. /**
  7. * 基于时间戳的4位自增序列和时间戳生成器
  8. * 规则:同一秒内序列号自增(0001-9999),下一秒序列重置为0001
  9. *
  10. * @author: wzq
  11. * @date: 2025/11/12
  12. */
  13. public class SequenceGenUtil {
  14. private static final AtomicInteger currentSequence = new AtomicInteger(0);
  15. private static volatile long lastSecond = -1L;
  16. private static final int MAX_SEQUENCE = 9999;
  17. // 时间格式化器(线程安全)
  18. private static final DateTimeFormatter TIMESTAMP_FORMATTER =
  19. DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
  20. /**
  21. * 序列号生成结果对象
  22. */
  23. @Getter
  24. public static class SequenceResult {
  25. private final String sequence; // 4位序列号,如 "0001"
  26. private final String timestamp; // 时间戳,如 "20251112154530"
  27. public SequenceResult(String sequence, String timestamp) {
  28. this.sequence = sequence;
  29. this.timestamp = timestamp;
  30. }
  31. /**
  32. * 获取完整编号:时间戳 + 序列号
  33. */
  34. public String getFullNumber() {
  35. return timestamp + sequence;
  36. }
  37. @Override
  38. public String toString() {
  39. return "SequenceResult{sequence='" + sequence + "', timestamp='" + timestamp + "'}";
  40. }
  41. }
  42. /**
  43. * 生成序列号和时间戳
  44. * 使用synchronized确保线程安全
  45. */
  46. public static synchronized SequenceResult generate() {
  47. long currentSecond = getCurrentSecond();
  48. String currentTimestamp = formatTimestamp(currentSecond);
  49. // 检查是否是新的一秒
  50. if (currentSecond != lastSecond) {
  51. currentSequence.set(0);
  52. lastSecond = currentSecond;
  53. }
  54. // 获取下一个序列值
  55. int seq = currentSequence.incrementAndGet();
  56. // 检查序列号是否溢出
  57. if (seq > MAX_SEQUENCE) {
  58. waitForNextSecond(currentSecond);
  59. // 递归调用,进入新秒后重新生成
  60. return generate();
  61. }
  62. // 格式化为4位数字并返回结果对象
  63. String sequenceStr = String.format("%04d", seq);
  64. return new SequenceResult(sequenceStr, currentTimestamp);
  65. }
  66. /**
  67. * 仅生成4位序列号(保持原有功能)
  68. */
  69. public static synchronized String generateSequenceOnly() {
  70. return generate().getSequence();
  71. }
  72. /**
  73. * 生成完整编号(时间戳+序列号)
  74. */
  75. public static synchronized String generateFullNumber() {
  76. return generate().getFullNumber();
  77. }
  78. /**
  79. * 获取当前时间的秒级时间戳
  80. */
  81. private static long getCurrentSecond() {
  82. return System.currentTimeMillis() / 1000;
  83. }
  84. /**
  85. * 将秒级时间戳格式化为 yyyyMMddHHmmss
  86. */
  87. private static String formatTimestamp(long timestampInSeconds) {
  88. LocalDateTime dateTime = LocalDateTime.ofEpochSecond(timestampInSeconds, 0,
  89. java.time.ZoneOffset.UTC);
  90. // 调整时区为系统默认时区
  91. return dateTime.atZone(java.time.ZoneId.systemDefault()).format(TIMESTAMP_FORMATTER);
  92. }
  93. /**
  94. * 等待下一秒(当序列号溢出时调用)
  95. */
  96. private static void waitForNextSecond(long currentSecond) {
  97. while (getCurrentSecond() <= currentSecond) {
  98. try {
  99. Thread.sleep(1);
  100. } catch (InterruptedException e) {
  101. Thread.currentThread().interrupt();
  102. throw new RuntimeException("序列生成器等待被中断", e);
  103. }
  104. }
  105. }
  106. /**
  107. * 重置生成器状态(主要用于测试)
  108. */
  109. public static synchronized void reset() {
  110. lastSecond = -1L;
  111. currentSequence.set(0);
  112. }
  113. public static void main(String[] args) {
  114. System.out.println("=== 生成序列号和时间戳 ===");
  115. // 生成完整的序列结果(包含序列号和时间戳)
  116. SequenceGenUtil.SequenceResult result1 = SequenceGenUtil.generate();
  117. System.out.println("序列号: " + result1.getSequence()); // 输出: 0001
  118. System.out.println("时间戳: " + result1.getTimestamp()); // 输出: 20251112154530
  119. System.out.println("完整编号: " + result1.getFullNumber()); // 输出: 202511121545300001
  120. System.out.println("完整对象: " + result1.toString());
  121. // 同一秒内连续生成
  122. System.out.println("\n=== 同一秒内连续生成 ===");
  123. for (int i = 0; i < 3; i++) {
  124. SequenceGenUtil.SequenceResult result = SequenceGenUtil.generate();
  125. System.out.println("时间戳: " + result.getTimestamp() + ", 序列号: " + result.getSequence());
  126. }
  127. // 仅生成序列号(保持原有功能)
  128. System.out.println("\n=== 仅生成序列号 ===");
  129. String sequenceOnly = SequenceGenUtil.generateSequenceOnly();
  130. System.out.println("仅序列号: " + sequenceOnly);
  131. // 生成完整编号
  132. System.out.println("\n=== 生成完整编号 ===");
  133. String fullNumber = SequenceGenUtil.generateFullNumber();
  134. System.out.println("完整编号: " + fullNumber);
  135. // 模拟跨秒生成
  136. System.out.println("\n=== 模拟跨秒生成 ===");
  137. SequenceGenUtil.SequenceResult beforeSleep = SequenceGenUtil.generate();
  138. System.out.println("休眠前: " + beforeSleep.getTimestamp() + " - " + beforeSleep.getSequence());
  139. try {
  140. Thread.sleep(1000); // 等待1秒
  141. } catch (InterruptedException e) {
  142. e.printStackTrace();
  143. }
  144. SequenceGenUtil.SequenceResult afterSleep = SequenceGenUtil.generate();
  145. System.out.println("休眠后: " + afterSleep.getTimestamp() + " - " + afterSleep.getSequence());
  146. }
  147. }