简介
本文基于Twitter的分布式ID生成策略,并做了一定的改动,以适应业务需要。
分布式ID生成的关键点:
- 全局唯一性;
- 生成速度;
- ID 所表达的含义;
功能:
分布式ID生成服务
- nextId() 新 ID ,线程安全
源码:
接口
/**
* <p>Function: ID 生成服务. </p>
* @author Dotions 2016年5月24日下午5:58:36
*/
public interface IdGenService {
public long nextId() throws Exception;
}
实现类
import java.util.HashSet;
import java.util.Set;
/**
* <p>
* Function: Twitter 的 ID 生成策略.<br/>
* 此实现中,简化了Twitter的生成策略。主要是取消了datacenter的标记,并将workerId值扩展到了1023。<br/>
* </p>
*
* @author Wang Yunfei 2016年5月24日下午6:00:31
*/
public class TwitterIdGenServiceImpl implements IdGenService {
private long workerId;
// 不用datacenter Id
// private long datacenterId;
private long sequence = 0L;
private long twepoch = 1288834974657L; // 起始标记点,作为基准
// private long workerIdBits = 5L;
// private long datacenterIdBits = 5L;
// 不需要datacenterId,只用workerId,扩展到10位
private long workerIdBits = 10L; // 只允许workid的范围为:0-1023
private long maxWorkerId = -1L ^ (-1L << workerIdBits);
// private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private long sequenceBits = 12L;
private long workerIdShift = sequenceBits;
// private long datacenterIdShift = sequenceBits + workerIdBits;
// private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private long timestampLeftShift = sequenceBits + workerIdBits;
private long sequenceMask = -1L ^ (-1L << sequenceBits);
private long lastTimestamp = -1L;
public TwitterIdGenServiceImpl(long workerId) {
super();
// sanity check for workerId
// 只允许workId的范围为:0-1023
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
this.workerId = workerId;
}
/**
* 下一个ID
* */
public long synchronized nextId() throws Exception {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new Exception(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 = 0;
}
lastTimestamp = timestamp;
return ((timestamp - twepoch) << timestampLeftShift) |
// (datacenterId << datacenterIdShift) |
(workerId << workerIdShift) | sequence;
}
/**
* 保证返回的毫秒数在参数之后
*
* @param lastTimestamp
* @return
*/
private static long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
/**
* 获得系统当前毫秒数
*
* @return
*/
private static long timeGen() {
return System.currentTimeMillis();
}
}
用法:
public static void main(String[] args) {
IdGenService idWorkder = new TwitterIdGenServiceImpl(0);
try {
Set<Long> set = new HashSet<Long>(100000);
for (int i = 0; i < 10000000; i++) {
set.add(idWorkder.nextId());
}
System.out.println(set.size());
} catch (Exception e) {
e.printStackTrace();
}
}