SnowFlakeUUidUtils.java 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. package com.fdkk.sxz.util;
  2. import com.github.pagehelper.util.StringUtil;
  3. import lombok.extern.log4j.Log4j2;
  4. import java.lang.management.ManagementFactory;
  5. import java.net.InetAddress;
  6. import java.net.NetworkInterface;
  7. import java.util.concurrent.TimeUnit;
  8. import java.util.concurrent.locks.Lock;
  9. import java.util.concurrent.locks.ReentrantLock;
  10. /**
  11. * 2 * @Author: Abner
  12. * 3 * @Date: 2020/12/9 16:07
  13. * 4
  14. */
  15. @Log4j2
  16. public class SnowFlakeUUidUtils {
  17. // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
  18. //起始标记点
  19. private final static long twepoch = 1288834974657L;
  20. // 机器标识位数
  21. private final static long workerIdBits = 5L;
  22. // 数据中心标识位数
  23. private final static long datacenterIdBits = 5L;
  24. // 机器ID最大值
  25. private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
  26. // 数据中心ID最大值
  27. private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
  28. // 毫秒内自增位
  29. private final static long sequenceBits = 12L;
  30. // 机器ID偏左移12位
  31. private final static long workerIdShift = sequenceBits;
  32. // 数据中心ID左移17位
  33. private final static long datacenterIdShift = sequenceBits + workerIdBits;
  34. // 时间毫秒左移22位
  35. private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
  36. private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
  37. private final static Lock myLock = new ReentrantLock();
  38. /* 上次生产id时间戳 */
  39. private static long lastTimestamp = -1L;
  40. // 0,并发控制
  41. private long sequence = 0L;
  42. private final long workerId;
  43. // 数据标识id部分
  44. private final long datacenterId;
  45. private static volatile SnowFlakeUUidUtils snowFlakeUUidUtils;
  46. private static SnowFlakeUUidUtils getSingleInstance(Long workerId, Long datacenterId){
  47. if(null == snowFlakeUUidUtils){
  48. synchronized (SnowFlakeUUidUtils.class){
  49. if(null == snowFlakeUUidUtils){
  50. if(null != workerId && null != datacenterId){
  51. snowFlakeUUidUtils = new SnowFlakeUUidUtils(workerId , datacenterId);
  52. }else{
  53. snowFlakeUUidUtils = new SnowFlakeUUidUtils();
  54. }
  55. }
  56. }
  57. }
  58. return snowFlakeUUidUtils;
  59. }
  60. /**
  61. * @param workerId 自定义的应用所在的服务器的机器ID,使用默认读取本机则无需传,传个NULL即可
  62. * @param datacenterId 自定义的应用所在的服务器的数据中心ID,使用默认读取本机则无需传,传个NULL即可
  63. * @param preStr 自定义的ID前缀
  64. * **/
  65. public static String generaUUid(Long workerId, Long datacenterId , String preStr){
  66. StringBuilder resultId = new StringBuilder();
  67. SnowFlakeUUidUtils snowFlakeUUidUtils = getSingleInstance(workerId , datacenterId);
  68. if(StringUtil.isNotEmpty(preStr)){
  69. return resultId.append(preStr).append(snowFlakeUUidUtils.nextId()).toString();
  70. }else{
  71. return resultId.append(snowFlakeUUidUtils.nextId()).toString();
  72. }
  73. }
  74. public SnowFlakeUUidUtils(){
  75. this.datacenterId = getDatacenterId(maxDatacenterId);
  76. this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
  77. }
  78. /**
  79. * @param workerId
  80. * 工作机器ID
  81. * @param datacenterId
  82. * 序列号
  83. */
  84. public SnowFlakeUUidUtils(long workerId, long datacenterId) {
  85. if (workerId > maxWorkerId || workerId < 0) {
  86. throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
  87. }
  88. if (datacenterId > maxDatacenterId || datacenterId < 0) {
  89. throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
  90. }
  91. this.workerId = workerId;
  92. this.datacenterId = datacenterId;
  93. }
  94. /**
  95. * 获取下一个ID
  96. * 线程安全
  97. * @return NULL 抢锁失败,需要重新调用
  98. * 数字串 抢锁成功,则生成20位的数字串
  99. */
  100. public Long nextId() {
  101. try {
  102. if(myLock.tryLock(700 , TimeUnit.MILLISECONDS)){
  103. try {
  104. long timestamp = timeGen();
  105. if (timestamp < lastTimestamp) {
  106. throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
  107. }
  108. if (lastTimestamp == timestamp) {
  109. // 当前毫秒内,则+1
  110. sequence = (sequence + 1) & sequenceMask;
  111. if (sequence == 0) {
  112. // 当前毫秒内计数满了,则等待下一秒
  113. timestamp = tilNextMillis(lastTimestamp);
  114. }
  115. } else {
  116. sequence = 0L;
  117. }
  118. lastTimestamp = timestamp;
  119. // ID偏移组合生成最终的ID,并返回ID
  120. Long nextId = ((timestamp - twepoch) << timestampLeftShift)
  121. | (datacenterId << datacenterIdShift)
  122. | (workerId << workerIdShift) | sequence;
  123. return nextId;
  124. }catch (Exception e){
  125. log.info("生成UUID抢锁失败:{}" , e);
  126. }finally {
  127. myLock.unlock();
  128. }
  129. }else{
  130. return null;
  131. }
  132. } catch (InterruptedException e) {
  133. e.printStackTrace();
  134. }
  135. return null;
  136. }
  137. private long tilNextMillis(final long lastTimestamp) {
  138. long timestamp = this.timeGen();
  139. while (timestamp <= lastTimestamp) {
  140. timestamp = this.timeGen();
  141. }
  142. return timestamp;
  143. }
  144. private long timeGen() {
  145. return System.currentTimeMillis();
  146. }
  147. /**
  148. * <p>
  149. * 获取 maxWorkerId
  150. * </p>
  151. */
  152. protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
  153. StringBuffer mpid = new StringBuffer();
  154. mpid.append(datacenterId);
  155. String name = ManagementFactory.getRuntimeMXBean().getName();
  156. if (!name.isEmpty()) {
  157. /*
  158. * GET jvmPid
  159. */
  160. mpid.append(name.split("@")[0]);
  161. }
  162. /*
  163. * MAC + PID 的 hashcode 获取16个低位
  164. */
  165. return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
  166. }
  167. /**
  168. * <p>
  169. * 数据标识id部分
  170. * </p>
  171. */
  172. protected static long getDatacenterId(long maxDatacenterId) {
  173. long id = 0L;
  174. try {
  175. InetAddress ip = InetAddress.getLocalHost();
  176. NetworkInterface network = NetworkInterface.getByInetAddress(ip);
  177. if (network == null) {
  178. id = 1L;
  179. } else {
  180. byte[] mac = network.getHardwareAddress();
  181. id = ((0x000000FF & (long) mac[mac.length - 1])
  182. | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
  183. id = id % (maxDatacenterId + 1);
  184. }
  185. } catch (Exception e) {
  186. System.out.println(" getDatacenterId: " + e.getMessage());
  187. }
  188. return id;
  189. }
  190. public static void main(String[] args) {
  191. for(int i = 0; i < 20; i++){
  192. System.out.println(SnowFlakeUUidUtils.generaUUid(null, null, null));
  193. }
  194. }
  195. }