雪花算法分析
- 首先,雪花算法有64位二进制数;从左往右数,
- 第1位是符号位(默认是零,不用做处理),
- 第2位~第42位(共41位),表示时间戳,因为41位二进制所能表达最大的数(十进制)是:2199023255551(单位是毫秒) 换算成年就是69.73057
- 第43位~第52位(共10位),这十位分成平均两段(也就是各五位)(那么前五位可以表示你在哪个机房,后五位可以表示你在某个机房的第几台机器;所以这十位就是自定义的,分布式微服务就需要
- 最后的12位,用于多个请求在同一毫秒内同时到达,需要给它们分配不同的id;范围是0~4095(4096种),所以在同一毫秒内,最多可以给4096给请求分配id,如果超过了那就强行让第4097个请求开始等待,等这一毫秒过了,才给分配id(后面有讲如何 强行等待)
public class Snowflake {
private final long unusedBits = 1L;
private final long timestampBits = 41L;
private final long datacenterIdBits = 5L;
private final long workerIdBits = 5L;
private final long sequenceBits = 12L;
private final long timestampShift = sequenceBits + datacenterIdBits + workerIdBits;
private final long datacenterIdShift = sequenceBits + workerIdBits;
private final long workerIdShift = sequenceBits;
private final long epoch = 1451606400000L;
private final long datacenterId;
private final long workerId;
private long sequence = 0L;
private long lastTimestamp = -1L;
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
private final long maxSequence = -1L ^ (-1L << sequenceBits);
public Snowflake(long datacenterId, long workerId) {
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(
String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(
String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
this.datacenterId = datacenterId;
this.workerId = workerId;
}
public synchronized long nextId() {
long currTimestamp = timestampGen();
if (currTimestamp < lastTimestamp) {
throw new IllegalStateException(
String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",
lastTimestamp - currTimestamp));
}
if (currTimestamp == lastTimestamp) {
sequence = (sequence + 1) & maxSequence;
if (sequence == 0) {
currTimestamp = waitNextMillis(currTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = currTimestamp;
return ((currTimestamp - epoch) << timestampShift) |
(datacenterId << datacenterIdShift) |
(workerId << workerIdShift) |
sequence;
}
protected long waitNextMillis(long currTimestamp) {
currTimestamp = timestampGen();
while (currTimestamp <= lastTimestamp) {
currTimestamp = timestampGen();
}
return currTimestamp;
}
public long timestampGen() {
return System.currentTimeMillis();
}
}