snow flake id生成
import java.util.concurrent.atomic.AtomicLong;
public class SnowFlakeUtils {
//比特位移位数
private final static int MACHINE_SHIFT = 10;
private final static int TIME_SHIFT = MACHINE_SHIFT + 12;
//每秒最多生成
private static final int MAX_SEQUENCE = 4095;
//生成码
private static AtomicLong sequence = new AtomicLong(-1);
//TODO 动态机器id
private static final long MACHINE_ID = machineId();
public static Long machineId() {
return 1L;
}
//防止时间回调标记
private static AtomicLong lastGenerateTime = new AtomicLong(timeForNow());
//时间回调自旋次数
private final static int MAX_ROLL_BACK_TRY_TIME = 5;
//时间回调自旋睡眠时间
private final static int ROLL_BACK_SLEEP_TIME = 1000;
/**
* 生成一个snow flake id
*
* @return snow flake id
*/
public static Long createId() {
//获取生成码与最新时间
long id = sequence.addAndGet(1);
long lastUpdateTime = timeForNow();
//时间回调尝试次数
int tryTime = 0;
for (; ; ) {
//出现时间回调,等待后再试
if (timeForNow() < lastGenerateTime.get()) {
try {
Thread.sleep(ROLL_BACK_SLEEP_TIME);
} catch (InterruptedException ignored) {
}
//尝试次数过多,抛出异常
if (tryTime++ > MAX_ROLL_BACK_TRY_TIME) {
throw new RuntimeException("time roll back");
}
} else {
//自旋次数表
int spin = 0;
for (; ; ) {
//生成码无溢出,生成交付
if (id <= MAX_SEQUENCE) {
//更新最后生成时间
if (lastUpdateTime > lastGenerateTime.get()) {
lastGenerateTime.set(lastUpdateTime);
}
return (lastUpdateTime << TIME_SHIFT | MACHINE_ID << MACHINE_SHIFT | id);
} else if (spin++ < 1000) {
//自旋时时间回调检查
if (timeForNow() < lastGenerateTime.get()){
break;
}
//生成码溢出自旋
//判断是否下一秒
if (timeForNow() > lastUpdateTime) {
//重置生成码
sequence.compareAndSet(id, -1);
//更新生成码
id = sequence.addAndGet(1);
//生成码正常,可更新最新时间避免生成码不正常更新卡时间外自旋
if (id < MAX_SEQUENCE) {
lastUpdateTime = timeForNow();
}
}
} else {
//自旋次数过多,休眠防止占用过高
try {
Thread.sleep(1);
} catch (InterruptedException ignored) {
}
spin = 0;
}
}
}
}
}
/**
* 获取最新时间
* 方便同步时间(复写,自定义时间
*
* @return
*/
public static Long timeForNow() {
return System.currentTimeMillis();
}
}
最近刚学了点并发就自己手搓一个雪花id生成了,应该是没什么问题的,还没学怎么单元测试,就逻辑上应该没什么问题<(。_。)>
结果又没有写作业,全在🦌代码o(╥﹏╥)o