-
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
