SnowflakeIdVariant.java 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. package com.ydtech.utils;
  2. import java.text.SimpleDateFormat;
  3. import java.util.Date;
  4. import java.util.HashSet;
  5. import java.util.Set;
  6. import java.util.concurrent.BrokenBarrierException;
  7. import java.util.concurrent.CyclicBarrier;
  8. import java.util.concurrent.TimeUnit;
  9. /**
  10. * Twitter_Snowflake<br>
  11. * SnowFlake改进符合业务的结构如下(每部分用-分开):<br>
  12. * bizCode(业务代码) + 201805051212(日期) + 4096(毫秒内随机数)<br>
  13. */
  14. /****
  15. * @ClassName: SnowflakeIdWorker
  16. * @Description:
  17. * @author ccc520
  18. * @date 2018年6月5日 上午8:44:27
  19. * @modificationHistory===============逻辑或功能性重大变更记录
  20. * @modify by user: (修改人)
  21. * @modify by reason: (修改原因)
  22. */
  23. public class SnowflakeIdVariant {
  24. // ==============================Fields===========================================
  25. /**
  26. * 序列在id中占的位数
  27. */
  28. private final long sequenceBits = 12L;
  29. /**
  30. * 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095)
  31. */
  32. private final long sequenceMask = -1L ^ (-1L << sequenceBits);
  33. /**
  34. * 毫秒内序列(0~4095)
  35. */
  36. private long sequence = 0L;
  37. /**
  38. * 上次生成ID的时间截
  39. */
  40. private long lastTimestamp = -1L;
  41. private static ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<SimpleDateFormat>() {
  42. @Override
  43. protected SimpleDateFormat initialValue() {
  44. return new SimpleDateFormat("yyyyMMddhhmmssSSS");
  45. }
  46. };
  47. //==============================Constructors=====================================
  48. /**
  49. * 构造函数
  50. */
  51. public SnowflakeIdVariant() {
  52. }
  53. // ==============================Methods==========================================
  54. /**
  55. * 获得下一个ID (该方法是线程安全的)
  56. *
  57. * @return SnowflakeId
  58. */
  59. public synchronized String nextId(String machineId, String bizCode) {
  60. long timestamp = timeGen();
  61. //如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
  62. if (timestamp < lastTimestamp) {
  63. throw new RuntimeException(
  64. String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
  65. }
  66. //如果是同一时间生成的,则进行毫秒内序列
  67. if (lastTimestamp == timestamp) {
  68. sequence = (sequence + 1) & sequenceMask;
  69. //毫秒内序列溢出
  70. if (sequence == 0) {
  71. //阻塞到下一个毫秒,获得新的时间戳
  72. timestamp = tilNextMillis(lastTimestamp);
  73. }
  74. }
  75. //时间戳改变,毫秒内序列重置
  76. else {
  77. sequence = 0L;
  78. }
  79. //上次生成ID的时间截
  80. lastTimestamp = timestamp;
  81. //移位并通过或运算拼到一起组成64位的ID
  82. // return bizCode + machineId + (threadLocal.get().format(new Date(timestamp))) + String.format("%05d",sequence);
  83. String precision = "5"; //几位序列号
  84. String format = "%0" + precision + "d";
  85. return bizCode + machineId + (threadLocal.get().format(new Date(timestamp))) + String.format(format, sequence);
  86. }
  87. /**
  88. * 阻塞到下一个毫秒,直到获得新的时间戳
  89. *
  90. * @param lastTimestamp 上次生成ID的时间截
  91. * @return 当前时间戳
  92. */
  93. protected long tilNextMillis(long lastTimestamp) {
  94. long timestamp = timeGen();
  95. while (timestamp <= lastTimestamp) {
  96. timestamp = timeGen();
  97. }
  98. return timestamp;
  99. }
  100. /**
  101. * 返回以毫秒为单位的当前时间
  102. *
  103. * @return 当前时间(毫秒)
  104. */
  105. protected long timeGen() {
  106. return System.currentTimeMillis();
  107. }
  108. //==============================Test=============================================
  109. /**
  110. * 测试
  111. */
  112. // public static void main(String[] args) throws InterruptedException {
  113. // System.out.println(SysConstants.MAC_ADDRESS);
  114. // String machineId = SysConstants.MAC_ADDRESS.replaceAll("-", "").substring(0,3);
  115. // SnowflakeIdVariant idWorker = new SnowflakeIdVariant();
  116. // long time1 = System.currentTimeMillis();
  117. // for (int i = 0; i < 100000; i++) {
  118. //// String id = idWorker.nextId("001","ORC");
  119. // String id = idWorker.nextId(machineId,"ORC");
  120. // //Thread.sleep(1);
  121. // System.out.println(id);
  122. // }
  123. // System.out.println(System.currentTimeMillis()-time1);
  124. // }
  125. // //////////// test ////////////
  126. public static void main(String[] args) throws Exception {
  127. final Set<String> set = new HashSet();
  128. SnowflakeIdVariant idWorker = new SnowflakeIdVariant();
  129. final CyclicBarrier cdl = new CyclicBarrier(100);
  130. for (int i = 0; i < 10000; i++) {
  131. new Thread(new Runnable() {
  132. @Override
  133. public void run() {
  134. try {
  135. cdl.await();
  136. } catch (InterruptedException e) {
  137. e.printStackTrace();
  138. } catch (BrokenBarrierException e) {
  139. e.printStackTrace();
  140. }
  141. // id
  142. String id = idWorker.nextId("001", "ORC");
  143. if (set.contains(id)) {
  144. System.out.println(id + " exists");
  145. }
  146. set.add(id);
  147. System.out.println(id);
  148. // id2
  149. String id2 = idWorker.nextId("001", "ORC");
  150. if (set.contains(id2)) {
  151. System.out.println(id2 + " exists");
  152. }
  153. set.add(id2);
  154. System.out.println(id2);
  155. }
  156. }).start();
  157. }
  158. try {
  159. TimeUnit.SECONDS.sleep(5);
  160. } catch (InterruptedException e) {
  161. e.printStackTrace();
  162. }
  163. }
  164. }