上代码
class CustomSnowFlake {
/**
* 开始时间
*/
private static final long startTimestamp = 1561077901000L;
/** 最后一次时间戳 */
private static long lastTimestamp = -1L;
// 序列号
private static long sequence = 0L;
private static final long sequenceBits = 12;
private static final long maxSequence = ~(-1L << sequenceBits);
/** 工作线程 */
private static final long workerIdBits = 5;
private static final long workerIdShift = sequenceBits;
private static final long maxWorkerId = ~(-1L << workerIdBits);
/** 数据中心 */
private static final long dataCenterIdBits = 5;
private static final long dataCenterIdShift = workerIdShift + workerIdBits;
private static final long maxDataCenterId = ~(-1L << dataCenterIdBits);
/** 时间戳 */
private static final long timestampShift = dataCenterIdShift + dataCenterIdBits;
private long dataCenterId;
private long workerId;
public CustomSnowFlake(long dataCenterId, long workerId) {
if (dataCenterId > maxDataCenterId || dataCenterId < 0) {
throw new IllegalArgumentException("数据中心id需要在0-31之间!");
}
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException("工作id需要在0-31之间!");
}
this.dataCenterId = dataCenterId;
this.workerId = workerId;
}
public synchronized long nextId() {
// 查看时间是否回流
long timestamp = getTimestamp();
if (timestamp < lastTimestamp) {
throw new RuntimeException("时间回调,拒绝生成id");
}
// 查看时间是否在同一毫秒内
if (timestamp == lastTimestamp) {
sequence = (sequence + 1) & maxSequence;
if (sequence == 0) {
timestamp = getNextMill();
sequence = 0;
}
} else {
sequence = 0;
}
lastTimestamp = timestamp;
return (timestamp - startTimestamp) << timestampShift
| dataCenterId << dataCenterIdShift
| workerId << workerIdShift
| sequence;
}
/**
* 获取下一毫秒
*
* @return 时间戳
*/
private long getNextMill() {
long timestamp = getTimestamp();
while (timestamp <= lastTimestamp) {
timestamp = getTimestamp();
}
return timestamp;
}
/**
* 时间戳
*
* @return 当前时间的时间戳
*/
private long getTimestamp() {
return System.currentTimeMillis();
}
}
测试
class Main {
public static void main(String[] args) {
m2();
}
private static void m2() {
final Set<Long> ids = new HashSet<>();
final CustomSnowFlake customSnowFlake = new CustomSnowFlake(1, 1);
int num = 10000;
for (int i = 0; i < num; i++) {
final long id = customSnowFlake.nextId();
ids.add(id);
System.out.println(System.currentTimeMillis()+"=="+id);
}
System.out.println(num == ids.size());
}
}
结果
问题
1、为啥用-1L进行位移,不用1L呢;(自己测试一下,便知其中奥妙!)
2、~(...) 这个符号的作用!(忍不住想说一下:跟 -1L^(...) 等价)
3、为啥 (sequence + 1) & sequenceMask; 有等于0的情况!(提示:位不够了,jvm默认不报错)
结论
1、约300个/毫秒
2、有14个字符,最多有19个,69年一轮回(画外音:我感觉应该弄成60,一个甲子吗);
3、按一个long类型长度(64位)计算;