snowFlakeId v2

这次也做了测试,没问题放心用ヾ(≧▽≦*)o

大概思路是维护一个Map,里面放了生成时间以及一个AtomicLong,需要生成时进入Map查找当前时间节点对应的AtomicLong,addAndGet确保一个时间戳内的机器生成码不重复,全程都使用自旋,无任何锁,避免了上锁带来的上下文切换资源消耗.

使用时记得修改获取机器码的方法


import java.util.LinkedHashMap;

import java.util.concurrent.atomic.AtomicInteger;

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 final int MAX_HISTORY_TIME = 5;

//TODO 动态机器id

private static final long MACHINE_ID = machineId();


private static Long machineId() {

return 1024L;

}


//时间与生成码的对应表

private static volatile LinkedHashMap<Long, AtomicLong> timeSet;


//标记最早的时间

private static Long earliestGenerateTime = timeForNow();


//放置同时修改不安全的LinkedHashMap

private static final AtomicInteger mapBusy = new AtomicInteger(0);


//时间回调自旋次数以及单次睡眠时间

private final static int MAX_ROLL_BACK_TRY_TIME = 5;

private final static int ROLL_BACK_SLEEP_TIME = 10;


//生成码超出范围自旋次数以及单次睡眠时间

private static final int SEQUENCE_MAX_SPIN = 1000;

private static final long SEQUENCE_MAX_SLEEP = 10;


/**

* 生成一个snow flake id

*

* @return snow flake id

*/

public static long createId() {

//获取最新时间

AtomicLong sequence;

long id;

int spin = 0;

long lastUpdateTime = timeForNow();

for (; ; ) {

//没有合集,创建

if (timeSet == null) {

if (mapBusy.get() == 0) {

createTimeSet();

}

} else if (timeSet.get(lastUpdateTime) == null && mapBusy.get() == 0) {

//没有这个时间戳,创建

createTimeStamp(lastUpdateTime);

} else if ((sequence = timeSet.get(lastUpdateTime)) != null) {

//生成码未满,返回

if ((id = sequence.addAndGet(1)) < MAX_SEQUENCE) {

return (lastUpdateTime << TIME_SHIFT | MACHINE_ID << MACHINE_SHIFT | id);

} else {

//生成码满,等待

if (spin++ >= SEQUENCE_MAX_SPIN) {

try {

Thread.sleep(SEQUENCE_MAX_SLEEP);

} catch (InterruptedException ignored) {


}

lastUpdateTime = timeForNow();

}

}

}

}

}


/**

* 生成这个时间戳的对应AtomicLong sequence

*

* @param currentTime 当前时间

*/

private static void createTimeStamp(Long currentTime) {

int rollBackTryTime = 0;

for (; ; ) {

if (timeSet == null) {

//timeSet懒加载,加载

createTimeSet();

} else if (currentTime < (earliestGenerateTime != null ? earliestGenerateTime : 0)) {

//时间回调,自旋尝试

try {

Thread.sleep(ROLL_BACK_SLEEP_TIME);

} catch (InterruptedException ignored) {


}

currentTime = timeForNow();

//尝试次数过多,抛出异常

if (rollBackTryTime++ >= MAX_ROLL_BACK_TRY_TIME) {

throw new RuntimeException("time roll back");

}

} else if (timeSet.get(currentTime) == null && mapBusy.compareAndSet(0, 1)) {

//生成当前时间cell

try {

if (timeSet.get(currentTime) == null) {

timeSet.putLast(currentTime, new AtomicLong(4094 - MAX_SEQUENCE));

final long[] smallestTime = new long[1];

timeSet.forEach((time, sequence) -> {

smallestTime[0] = (smallestTime[0] == 0) ? time : smallestTime[0];

smallestTime[0] = (smallestTime[0] < time) ? smallestTime[0] : time;

});

earliestGenerateTime = smallestTime[0];

//移除最早时间

if (timeSet.size() > MAX_HISTORY_TIME) {

timeSet.pollFirstEntry();

}

}

} finally {

mapBusy.set(0);

}

return;

} else if (timeSet.get(currentTime) != null) {

return;

}

}

}


/**

* 创建时间合集

*/

private static void createTimeSet() {

initCheck();

for (; ; ) {

//上锁保护安全

if (mapBusy.get() == 0 && timeSet == null && mapBusy.compareAndSet(0, 1)) {

if (timeSet == null) {

try {

timeSet = new LinkedHashMap<>();

timeSet.putLast(0L, null);

} finally {

mapBusy.set(0);

}

}

} else if (timeSet != null) {

return;

}

}

}


/**

* 获取最新时间

* 方便同步时间(复写,自定义时间

*

* @return 当前时间

*/

private static Long timeForNow() {

return System.currentTimeMillis();

}


/**

* 基本数值检查

*/

private static void initCheck() {

if (MACHINE_ID > 1024) throw new RuntimeException("machine id out of max, max 1023");

if (MAX_SEQUENCE > 4095) throw new RuntimeException("sequence out of max, max 4095");

}

}


/static/3fcd3ff43f3d2163c43161153ec6c673da670be2e409ab941604d040df91015e.png

/static/2f033d6b8a4f865770b7dfd1d5b327ee592d3b10e0594b31e2a76982b7f427f4.png

/static/47a5a8de9779a4acf658a5a0ab4eecbe64146b9e4adbc3e28742f5b3bdb1a14e.png/static/f4fdf13119947d9c39af935d593d25b3b4d4faf6c6dea08f9ed81b186594471e.png

发布评论
全部评论(0)
最新
最早
加载中...