twitter的SnowFlake生成ID能够按照时间有序
生成
SnowFlake算法生成id的结果是一个64bit
大小的整数
分布式系统内不会产生重复id
(用有datacenterId和workerId来做区分)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
| package com.zby.util;
import org.springframework.context.annotation.Bean;
import java.lang.management.ManagementFactory; import java.net.InetAddress; import java.net.NetworkInterface;
public class IdWorker { private final static long twepoch = 1554879344774L; private final static long workerIdBits = 5L; private final static long datacenterIdBits = 5L; private final static long maxWorkerId = -1L ^ (-1L << workerIdBits); private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); private final static long sequenceBits = 12L; private final static long workerIdShift = sequenceBits; private final static long datacenterIdShift = sequenceBits + workerIdBits; private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private final static long sequenceMask = -1L ^ (-1L << sequenceBits); private static long lastTimestamp = -1L; private long sequence = 0L;
private final long workerId; private final long datacenterId;
public IdWorker(){ this.datacenterId = getDatacenterId(maxDatacenterId); this.workerId = getMaxWorkerId(datacenterId, maxWorkerId); }
public IdWorker(long workerId, long datacenterId) { if (workerId > maxWorkerId workerId < 0) { throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId)); } if (datacenterId > maxDatacenterId datacenterId < 0) { throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId)); } this.workerId = workerId; this.datacenterId = datacenterId; }
@Bean public synchronized long nextId() { long timestamp = timeGen(); if (timestamp < lastTimestamp) { throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); }
if (lastTimestamp == timestamp) { sequence = (sequence + 1) & sequenceMask; if (sequence == 0) { timestamp = tilNextMillis(lastTimestamp); } } else { sequence = 0L; } lastTimestamp = timestamp; long nextId = ((timestamp - twepoch) << timestampLeftShift) (datacenterId << datacenterIdShift) (workerId << workerIdShift) sequence;
return nextId; }
private long tilNextMillis(final long lastTimestamp) { long timestamp = this.timeGen(); while (timestamp <= lastTimestamp) { timestamp = this.timeGen(); } return timestamp; }
private long timeGen() { return System.currentTimeMillis(); }
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) { StringBuffer mpid = new StringBuffer(); mpid.append(datacenterId); String name = ManagementFactory.getRuntimeMXBean().getName(); if (!name.isEmpty()) {
mpid.append(name.split("@")[0]); }
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1); }
protected static long getDatacenterId(long maxDatacenterId) { long id = 0L; try { InetAddress ip = InetAddress.getLocalHost(); NetworkInterface network = NetworkInterface.getByInetAddress(ip); if (network == null) { id = 1L; } else { byte[] mac = network.getHardwareAddress(); id = ((0x000000FF & (long) mac[mac.length - 1]) (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6; id = id % (maxDatacenterId + 1); } } catch (Exception e) { System.out.println(" getDatacenterId: " + e.getMessage()); } return id; } }
|