1. import java.lang.management.ManagementFactory;
    2. import java.net.InetAddress;
    3. import java.net.NetworkInterface;
    4. /**
    5. * <p>名称:IdWorker.java</p>
    6. * <p>描述:分布式自增长ID</p>
    7. * <pre>
    8. * Twitter的 Snowflake JAVA实现方案
    9. * </pre>
    10. * 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:
    11. * 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
    12. * 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,
    13. * 然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),
    14. * 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
    15. * 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),
    16. * 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
    17. * <p>
    18. * 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))
    19. *
    20. * @author 黑马程序员
    21. */
    22. public class IdWorker {
    23. // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
    24. private final static long twepoch = 1288834974657L;
    25. // 机器标识位数
    26. private final static long workerIdBits = 5L;
    27. // 数据中心标识位数
    28. private final static long datacenterIdBits = 5L;
    29. // 机器ID最大值
    30. private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
    31. // 数据中心ID最大值
    32. private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
    33. // 毫秒内自增位
    34. private final static long sequenceBits = 12L;
    35. // 机器ID偏左移12位
    36. private final static long workerIdShift = sequenceBits;
    37. // 数据中心ID左移17位
    38. private final static long datacenterIdShift = sequenceBits + workerIdBits;
    39. // 时间毫秒左移22位
    40. private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
    41. private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
    42. /* 上次生产id时间戳 */
    43. private static long lastTimestamp = -1L;
    44. // 0,并发控制
    45. private long sequence = 0L;
    46. private final long workerId;
    47. // 数据标识id部分
    48. private final long datacenterId;
    49. public IdWorker(){
    50. this.datacenterId = getDatacenterId(maxDatacenterId);
    51. this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
    52. }
    53. /**
    54. * @param workerId
    55. * 工作机器ID
    56. * @param datacenterId
    57. * 序列号
    58. */
    59. public IdWorker(long workerId, long datacenterId) {
    60. if (workerId > maxWorkerId || workerId < 0) {
    61. throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
    62. }
    63. if (datacenterId > maxDatacenterId || datacenterId < 0) {
    64. throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
    65. }
    66. this.workerId = workerId;
    67. this.datacenterId = datacenterId;
    68. }
    69. /**
    70. * 获取下一个ID
    71. *
    72. * @return
    73. */
    74. public synchronized long nextId() {
    75. long timestamp = timeGen();
    76. if (timestamp < lastTimestamp) {
    77. throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
    78. }
    79. if (lastTimestamp == timestamp) {
    80. // 当前毫秒内,则+1
    81. sequence = (sequence + 1) & sequenceMask;
    82. if (sequence == 0) {
    83. // 当前毫秒内计数满了,则等待下一秒
    84. timestamp = tilNextMillis(lastTimestamp);
    85. }
    86. } else {
    87. sequence = 0L;
    88. }
    89. lastTimestamp = timestamp;
    90. // ID偏移组合生成最终的ID,并返回ID
    91. long nextId = ((timestamp - twepoch) << timestampLeftShift)
    92. | (datacenterId << datacenterIdShift)
    93. | (workerId << workerIdShift) | sequence;
    94. return nextId;
    95. }
    96. private long tilNextMillis(final long lastTimestamp) {
    97. long timestamp = this.timeGen();
    98. while (timestamp <= lastTimestamp) {
    99. timestamp = this.timeGen();
    100. }
    101. return timestamp;
    102. }
    103. private long timeGen() {
    104. return System.currentTimeMillis();
    105. }
    106. /**
    107. * <p>
    108. * 获取 maxWorkerId
    109. * </p>
    110. */
    111. protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
    112. StringBuffer mpid = new StringBuffer();
    113. mpid.append(datacenterId);
    114. String name = ManagementFactory.getRuntimeMXBean().getName();
    115. if (!name.isEmpty()) {
    116. /*
    117. * GET jvmPid
    118. */
    119. mpid.append(name.split("@")[0]);
    120. }
    121. /*
    122. * MAC + PID 的 hashcode 获取16个低位
    123. */
    124. return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
    125. }
    126. /**
    127. * <p>
    128. * 数据标识id部分
    129. * </p>
    130. */
    131. protected static long getDatacenterId(long maxDatacenterId) {
    132. long id = 0L;
    133. try {
    134. InetAddress ip = InetAddress.getLocalHost();
    135. NetworkInterface network = NetworkInterface.getByInetAddress(ip);
    136. if (network == null) {
    137. id = 1L;
    138. } else {
    139. byte[] mac = network.getHardwareAddress();
    140. id = ((0x000000FF & (long) mac[mac.length - 1])
    141. | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
    142. id = id % (maxDatacenterId + 1);
    143. }
    144. } catch (Exception e) {
    145. System.out.println(" getDatacenterId: " + e.getMessage());
    146. }
    147. return id;
    148. }
    149. }