- public class IdGenerator {
-
-
private final static long beginTs = 1483200000000L; -
-
private long lastTs = 0L; -
-
private long processId; -
private int processIdBits = 10; -
-
private long sequence = 0L; -
private int sequenceBits = 12; -
-
public IdGenerator() { -
} -
-
public IdGenerator(long processId) { -
if (processId > ((1 << processIdBits) - 1)) { -
throw new RuntimeException("进程ID超出范围,设置位数" + processIdBits + ",最大" + ((1 << processIdBits) - 1)); -
} -
this.processId = processId; -
} -
-
protected long timeGen() { -
return System.currentTimeMillis(); -
} -
-
public synchronized long nextId() { -
long ts = timeGen(); -
// 刚刚生成的时间戳比上次的时间戳还小,出错 -
if (ts < lastTs) { -
throw new RuntimeException("时间戳顺序错误"); -
} -
// 刚刚生成的时间戳跟上次的时间戳一样,则需要生成一个sequence序列号 -
if (ts == lastTs) { -
// sequence循环自增 -
sequence = (sequence + 1) & ((1 << sequenceBits) - 1); -
// 如果sequence=0则需要重新生成时间戳 -
if (sequence == 0) { -
// 且必须保证时间戳序列往后 -
ts = nextTs(lastTs); -
} -
// 如果ts>lastTs,时间戳序列已经不同了,此时可以不必生成sequence了,直接取0 -
} else { -
sequence = 0L; -
} -
// 更新lastTs时间戳 -
lastTs = ts; -
return ((ts - beginTs) << (processIdBits + sequenceBits)) | (processId << sequenceBits) | sequence; -
} -
-
public Long nextShortId() { -
Long shortId = System.currentTimeMillis() / 100 % 1000000000; -
if (shortId < 100000000) { -
shortId += 100000000; -
} -
return shortId; -
} -
-
protected long nextTs(long lastTs) { -
long ts = timeGen(); -
while (ts <= lastTs) { -
ts = timeGen(); -
} -
return ts; -
} -
-
}
试一下这个算法的效率:
-
public static void main(String[] args) throws Exception { -
// TODO Auto-generated method stub -
IdGenerator ig = new IdGenerator(1023); -
Long start = System.currentTimeMillis(); -
Set<Long> set = new HashSet<Long>(); -
for (int i = 0; i < 100000; i++) { -
set.add(ig.nextId()); -
} -
System.out.println(set.size()); -
System.out.println(System.currentTimeMillis() - start); -
}
结果:
set.size(): 100000
time:115