根据项目实际情况,参考雪花id生成算法写的,定位为嵌入式,可以用做分布式,针对单机多实例的情况做了优化兼容。
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class UuidGenerator {
private UuidGenerator() {
}
public static long getNextId() {
return UuidInstance.INSTANCE.genUuid();
}
public static long getNextId(long workerId, long progressId) {
return UuidInstance.INSTANCE.genUuid(workerId, progressId);
}
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
for (int i = 0; i < 8000; i++) {
UuidGenerator.getNextId();
}
long end = System.currentTimeMillis();
System.out.println("用时:" + (end - start));
}
private static class UuidInstance {
public static long sequenceBits = 3L;
public static long progressIdBits = 10L;
public static long workerIdBits = 10L;
public static long timestampBits = 40L;
public static long blankBits = 1L;
public static long progressIdMask = ~(-1L << (progressIdBits));
public static long workerIdMask = ~(-1L << workerIdBits);
public static long sequenceMask = ~(-1L << (sequenceBits));
public static long progressIdShift = sequenceBits;
public static long workerIdShift = progressIdShift + progressIdBits;
public static long timestampLeftShift = workerIdShift + workerIdBits;
private long sequence = 0L;
private int vibrance = 0;
public static long twepoch = 1609430400000L;
private long lastTimestamp = -1L;
private long workerId = 0L;
private long progressId = 0L;
private Lock lock = new ReentrantLock();
private static final UuidInstance INSTANCE = new UuidInstance();
{
try {
byte[] macAddress = NetworkInterface.getByInetAddress(InetAddress.getLocalHost()).getHardwareAddress();
if (macAddress == null || macAddress.length < 2) {
throw new RuntimeException("UuidGenerator:get macAddress error!");
}
workerId = (((0x000000FF & (long) macAddress[macAddress.length - 2]) | (0x0000FF00 & (((long) macAddress[macAddress.length - 1]) << 8))) >> 6) % (workerIdMask + 1);
String name = ManagementFactory.getRuntimeMXBean().getName();
StringBuilder sb = new StringBuilder();
sb.append(workerId);
if(null == name || "".equals(name)){
sb.append(name.split("@")[0]);
}
int hashCode = sb.toString().hashCode();
int i = hashCode & 0xffff;
progressId = i % (progressIdMask + 1);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private long genUuid() {
return nextId();
}
private long genUuid(long workerId, long progressId) {
if (progressId != 0L) {
this.progressId = progressId;
}
if (workerId != 0L) {
this.workerId = workerId;
}
return nextId();
}
private long nextId() {
lock.lock();
try {
long timestamp = getTimestamp();
timestamp = checkTime(timestamp);
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
this.sequence = ~vibrance & 1;
}
lastTimestamp = timestamp;
return ((timestamp - twepoch) << timestampLeftShift)
| (workerId & workerIdMask) << workerIdShift
| (progressId & progressIdMask) << progressIdShift
| sequence;
} finally {
lock.unlock();
}
}
private long checkTime(long timestamp) {
if (timestamp < lastTimestamp) {
long offset = lastTimestamp - timestamp;
if (offset <= 5) {
try {
wait(offset << 1);
timestamp = getTimestamp();
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format("uuid gen error ,time return back for %d millisecond", lastTimestamp - timestamp));
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} else {
throw new RuntimeException(String.format("uuid gen error ,time return back for %d millisecond", lastTimestamp - timestamp));
}
}
return timestamp;
}
private long tilNextMillis(long lastTimestamp) {
long timestamp = getTimestamp();
while (timestamp <= lastTimestamp) {
timestamp = getTimestamp();
}
return timestamp;
}
private long getTimestamp() {
return System.currentTimeMillis();
}
}
}
|