Vesta发号器源码解析——AtomicIdPopulator
这个类是核心的,用于生成ID的关键类之一,是一个实现了IdPopulator, ResetPopulator接口的ID生成类
内部类Variant
这个类用于持有在一个生成周期内的上一次时间戳以及当前的序列值
class Variant {
private long sequence = 0;
private long lastTimestamp = -1;
}
//利用AtomicReference引用Variant进行操作保证原子性
private AtomicReference<Variant> variant = new AtomicReference<Variant>(new Variant());
构造方法
public AtomicIdPopulator() {
super();
}
populateId方法
核心方法,生成Id中的主要动态部分,时间和序列号
public void populateId(Timer timer, Id id, IdMeta idMeta) {
//新老两个准备好
Variant varOld, varNew;
//临时性的变量存储时间戳和序列值
long timestamp, sequence;
//不断尝试 直到出现退出条件break
while (true) {
//先存好旧的variant
varOld = variant.get();
// 生成当前的variant
//首先是当前周期的时间戳,区分毫秒级和秒级,在timer中实现
timestamp = timer.genTime();
//校验时间戳,具体实现在timer中,用于确保使用时间没有超限制
timer.validateTimestamp(varOld.lastTimestamp, timestamp);
//记录原始的sequence
sequence = varOld.sequence;
//判断是否位于同一个周期内,是的话累加sequ否则重置sequence
if (timestamp == varOld.lastTimestamp) {
//sequence累加
sequence++;
//确保sequence没有超过限制,超限会导致sequence变成0
sequence &= idMeta.getSeqBitsMask();
if (sequence == 0) {
//超过限制了,等待下一个周期来临,直到来临后返回新的时间戳
timestamp = timer.tillNextTimeUnit(varOld.lastTimestamp);
}
} else {
//不在同一个周期,重置sequence
sequence = 0;
}
// 利用原子操作类的CAS特性更新variant
varNew = new Variant();
varNew.sequence = sequence;
varNew.lastTimestamp = timestamp;
if (variant.compareAndSet(varOld, varNew)) {
//更新成功后,组装传进来的id
id.setSeq(sequence);
id.setTime(timestamp);
//ID生成成功,退出循环
break;
}
}
}
Reset方法
用于在下个时间周期来临的时候重置当先的variant,从而能够为后续的周期服务
public void reset() {
variant = new AtomicReference<Variant>(new Variant());
}
网友评论