import java.util.concurrent.ConcurrentHashMap;
/**
* @author L.yn
* @date 2021-07-19 10:34
*/
public class SnowflakeIdHolder {
private SnowflakeIdHolder() {
}
private static final ConcurrentHashMap<String, SnowflakeIdUtils> HOLDER = new ConcurrentHashMap<>();
public static SnowflakeIdUtils getSnowflakeIdUtils(String name) {
SnowflakeIdUtils snowflakeIdUtils = HOLDER.get(name);
if (snowflakeIdUtils == null) {
snowflakeIdUtils = HOLDER.computeIfAbsent(name, n -> new SnowflakeIdUtils(SnowflakeIdConfig.getWorkerId()));
}
return snowflakeIdUtils;
}
/**
* 生成下一个雪花ID
*
* @return 唯一雪花id
*/
public static long genId(String name) {
return getSnowflakeIdUtils(name).genId();
}
// /**
// * 生成易识别的下一个雪花ID,目前会重复,不建议使用
// *
// * @return 唯一雪花id
// */
// @Deprecated
// public static long genFormatId(String name) {
// return getSnowflakeIdUtils(name).genFormatId();
// }
//
// /**
// * 生成易识别的下一个雪花ID
// *
// * @return 唯一雪花id
// */
// public static String genFormatIdStr(String name) {
// return getSnowflakeIdUtils(name).genFormatIdStr();
// }
}
/**
* @author L.yn
* @date 2021-07-19 10:34
*/
@Slf4j
public class SnowflakeIdConfig implements InitializingBean {
private static int workGroupIdBits = 2;
private static String localIp;
static {
String ip = null;
try {
ip = getIp();
} catch (SocketException e) {
e.printStackTrace();
}
if (ip == null) {
WORKER_ID = (int) (Math.random() * SnowflakeIdUtils.MAX_WORKER_ID);
log.error("生成机器编号失败,本机ip解析失败,ip:{}", ip);
System.exit(500);
} else {
WORKER_ID = toWorkId(ip);
}
}
private static final int WORKER_ID;
public static int getWorkerId() {
return WORKER_ID;
}
public static synchronized String getIp() throws SocketException {
if (localIp != null) {
return localIp;
}
// 本地IP,如果没有配置外网IP则返回它
String localIp = null;
// 外网IP
String netIp = null;
Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces();
InetAddress ip;
// 是否找到外网IP
boolean find = false;
while (netInterfaces.hasMoreElements() && !find) {
NetworkInterface ni = netInterfaces.nextElement();
Enumeration<InetAddress> address = ni.getInetAddresses();
while (address.hasMoreElements()) {
ip = address.nextElement();
// 外网IP
if (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress()
&& !ip.getHostAddress().contains(":")) {
netIp = ip.getHostAddress();
find = true;
break;
} else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress()
&& !ip.getHostAddress().contains(":") && localIp == null) {
localIp = ip.getHostAddress();
}
}
}
if (netIp != null && !"".equals(netIp)) {
localIp = netIp;
return netIp;
} else {
localIp = localIp;
return localIp;
}
}
static int toWorkId(String ip) {
//1.获取本机ip
//2.转换为数字
String[] split = ip.split("\\.");
if (split.length != 4) {
log.error("生成机器编号失败,本机ip解析失败,ip:{}", ip);
System.exit(500);
} else {
//3.按高低位拆成前后2部分
//4.高低位再分高低位与或
int high = (Integer.parseInt(split[0]) ^ Integer.parseInt(split[1]));
int low = (Integer.parseInt(split[2]) << 8) + Integer.parseInt(split[3]);
int workGroupMax = ~(-1 << workGroupIdBits);
String groupId = System.getenv("SNOWFLAKE_GROUP_ID");
if (groupId == null) {
groupId = String.valueOf(high);
}
String snowflakeGroupIdStr = groupId.trim();
int snowflakeGroupId = high;
try {
snowflakeGroupId = Integer.parseInt(snowflakeGroupIdStr);
} catch (NumberFormatException e) {
log.error("填写集群组id解析失败,{}", snowflakeGroupIdStr);
System.exit(501);
}
//5.2部分分别按范围取模
int workGroupId = snowflakeGroupId & workGroupMax;
int moveBit = SnowflakeIdUtils.WORKER_ID_BITS - workGroupIdBits;
int machineId = (((low & (-1 << 8))) & (~(-1 << moveBit))) + (low & (~(-1 << 8)));
//6.组合生成机器id
return (workGroupId << moveBit) + machineId;
}
return (int) (Math.random() * SnowflakeIdUtils.MAX_WORKER_ID);
}
@Override
public void afterPropertiesSet() throws Exception {
log.info("根据当前机器ip:{} 生成机器码:{}", getIp(), getWorkerId());
}
}
/**
* 主引用与次引用都是long
*
* @author L.yn
* @date 2021-07-19 10:34
*/
public class AtomicLongAndLong {
private volatile long[] ref;
protected static final Unsafe UNSAFE = reflectGetUnsafe();
protected static final long REF_OFFSET =
objectFieldOffset(UNSAFE, "ref", BaseAtomicPrimaryAndSecondaryReferences.class);
public AtomicLongAndLong(long main, long minor) {
this.ref = new long[]{main, minor};
}
public void setMain(long main) {
set(main, ref[0]);
}
public void setMinor(long minor) {
set(ref[0], minor);
}
public void set(long main, long minor) {
if (main != ref[0] || minor != ref[1]) {
ref = new long[]{main, minor};
}
}
public long getMinor() {
return ref[1];
}
public long getMain() {
return ref[0];
}
public boolean compareAndSetMain(long expectedMain, long newMain) {
return compareAndSet(expectedMain, newMain, ref[1], ref[1]);
}
public boolean compareAndSetMain(long expectedMain, long newMain, long newMinor) {
long[] currentRef = this.ref;
return expectedMain == currentRef[0]
&& (newMain == currentRef[1]
|| casSet(currentRef, new long[]{newMain, newMinor}));
}
public boolean compareAndSetMinor(long expectedMain, long expectedMinor, long newMinor) {
return compareAndSet(expectedMain, expectedMain, expectedMinor, newMinor);
}
public boolean compareAndSetMinor(long expectedMinor, long newMinor) {
return compareAndSet(ref[0], ref[0], expectedMinor, newMinor);
}
public boolean compareAndSet(long expectedMain, long newMain, long expectedMinor, long newMinor) {
long[] currentRef = this.ref;
return expectedMain == currentRef[0]
&& expectedMinor == currentRef[1]
&& ((newMain == currentRef[0]
&& newMinor == currentRef[1])
|| casSet(currentRef, new long[]{newMain, newMinor}));
}
public final long getAndDecrementMain() {
return getAndAddMain(-1);
}
public final long decrementAndGetMain() {
return addAndGetMain(-1);
}
public final long getAndIncrementMain() {
return getAndAddMain(1);
}
public final long incrementAndGetMain() {
return addAndGetMain(1);
}
public final long getAndAddMain(long add) {
long currentMain, currentMinor;
do {
currentMain = getMain();
currentMinor = getMinor();
} while (!compareAndSetMain(currentMain, currentMain + add, currentMinor));
return currentMain;
}
public final long addAndGetMain(long add) {
return getAndAddMain(add) + add;
}
public final long getAndDecrementMinor() {
return getAndAddMinor(-1);
}
public final long decrementAndGetMinor() {
return addAndGetMinor(-1);
}
public final long getAndIncrementMinor() {
return getAndAddMinor(1);
}
public final long incrementAndGetMinor() {
return addAndGetMinor(1);
}
public final long getAndAddMinor(long add) {
long currentMain, currentMinor;
do {
currentMain = getMain();
currentMinor = getMinor();
} while (!compareAndSetMinor(currentMain, currentMinor, currentMinor + add));
return currentMinor;
}
public final long addAndGetMinor(long add) {
return getAndAddMinor(add) + add;
}
private boolean casSet(long[] expectedRef, long[] newRef) {
return UNSAFE.compareAndSwapObject(this, REF_OFFSET, expectedRef, newRef);
}
private static Unsafe reflectGetUnsafe() {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
return (Unsafe) field.get(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
static long objectFieldOffset(Unsafe unsafe, String field, Class<?> clazz) {
try {
return unsafe.objectFieldOffset(clazz.getDeclaredField(field));
} catch (NoSuchFieldException e) {
// Convert Exception to corresponding Error
NoSuchFieldError error = new NoSuchFieldError(field);
error.initCause(e);
throw error;
}
}
}
/**
* 相互关联的原子操作类
*
* @param <MAIN> 主引用,更新时必须携带次引用一起更新
* @param <MINOR> 次引用,可独立更新,无需更新主引用
* @author L.yn
* @date 2021-07-19 10:34
*/
public abstract class BaseAtomicPrimaryAndSecondaryReferences<MAIN, MINOR> {
private volatile PrimaryAndSecondaryReferences<MAIN, MINOR> ref;
protected static final Unsafe UNSAFE = reflectGetUnsafe();
protected static final long REF_OFFSET =
objectFieldOffset(UNSAFE, "ref", BaseAtomicPrimaryAndSecondaryReferences.class);
public BaseAtomicPrimaryAndSecondaryReferences(MAIN main, MINOR minor) {
this.ref = PrimaryAndSecondaryReferences.of(main, minor);
}
public void set(MAIN main, MINOR minor) {
if (main != ref.main || minor != ref.minor) {
ref = PrimaryAndSecondaryReferences.of(main, minor);
}
}
public MINOR getMinor() {
return ref.minor;
}
public MAIN getMain() {
return ref.main;
}
public boolean compareAndSetMain(MAIN expectedMain, MAIN newMain, MINOR newMinor) {
return compareAndSet(expectedMain, newMain, ref.minor, newMinor);
}
public boolean compareAndSetMinor(MAIN expectedMain, MINOR expectedMinor, MINOR newMinor) {
return compareAndSet(expectedMain, expectedMain, expectedMinor, newMinor);
}
public boolean compareAndSet(MAIN expectedMain, MAIN newMain, MINOR expectedMinor, MINOR newMinor) {
PrimaryAndSecondaryReferences<MAIN, MINOR> currentRef = this.ref;
boolean b1 = expectedMain == currentRef.main
&& expectedMinor == currentRef.minor;
boolean b2 = newMain == currentRef.main
&& newMinor == currentRef.minor;
return b1 && (b2
|| casSet(currentRef, PrimaryAndSecondaryReferences.of(newMain, newMinor)));
}
private boolean casSet(PrimaryAndSecondaryReferences<MAIN, MINOR> expectedRef, PrimaryAndSecondaryReferences<MAIN, MINOR> newRef) {
return UNSAFE.compareAndSwapObject(this, REF_OFFSET, expectedRef, newRef);
}
private static Unsafe reflectGetUnsafe() {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
return (Unsafe) field.get(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
static long objectFieldOffset(Unsafe unsafe, String field, Class<?> clazz) {
try {
return unsafe.objectFieldOffset(clazz.getDeclaredField(field));
} catch (NoSuchFieldException e) {
// Convert Exception to corresponding Error
NoSuchFieldError error = new NoSuchFieldError(field);
error.initCause(e);
throw error;
}
}
private static class PrimaryAndSecondaryReferences<MAIN, MINOR> {
private volatile MAIN main;
private volatile MINOR minor;
private PrimaryAndSecondaryReferences(MAIN main, MINOR minor) {
this.minor = minor;
this.main = main;
}
static <MAIN, MINOR> PrimaryAndSecondaryReferences<MAIN, MINOR> of(MAIN main, MINOR minor) {
return new PrimaryAndSecondaryReferences<>(main, minor);
}
@Override
public String toString() {
return "PrimaryAndSecondaryReferences{" + "main=" + main + ", minor=" + minor + '}';
}
}
}
/**
* @author L.yn
* @date 2021-07-19 10:34
*/
public class SnowflakeIdUtils {
/**
* 参考时间戳
*/
public static final long REFERENCE_TIME;
static {
Calendar time = Calendar.getInstance();
/*这里需要用想要的年份减去1900年,Date类就是这么规定的*/
time.set(2010, Calendar.JANUARY, 1);
REFERENCE_TIME = time.getTimeInMillis();
}
/**
* 机器回退容忍毫秒数
*/
public static final int FALLBACK_ACCEPT_MILLISECONDS = 100;
/**
* 空闲位
*/
public static final int FREE_BITS = 1;
/**
* 时间戳占据位数,不要修改
*/
public static final int TIMESTAMP_BITS = 41;
/**
* 机器id所占的位数</br>
* 机器数量少时,生成效率不够可以改小一点</br>
* 推荐最少6位,最多12位
*/
public static final int WORKER_ID_BITS = 13;
/**
* 序列在id中占的位数
*/
public static final int SERIAL_NUMBER_BITS = Long.SIZE - FREE_BITS - TIMESTAMP_BITS - WORKER_ID_BITS;
/**
* 时间左移位数,固定值22
*/
public static final int TIMESTAMP_OFFSET = Long.SIZE - FREE_BITS - TIMESTAMP_BITS;
/**
* 机器ID向左移位数
*/
public static final int WORKER_ID_OFFSET = Long.SIZE - FREE_BITS - TIMESTAMP_BITS - WORKER_ID_BITS;
/**
* 自增序列向左移位数
*/
public static final int SERIAL_NUMBER_OFFSET =
Long.SIZE - FREE_BITS - TIMESTAMP_BITS - WORKER_ID_BITS - SERIAL_NUMBER_BITS;
/**
* 支持的最大数据机器id
*/
public static final int MAX_WORKER_ID = ~(-1 << WORKER_ID_BITS);
/**
* 每毫秒自增最大数量
*/
public static final int SERIAL_NUMBER_MAX = ~(-1 << SERIAL_NUMBER_BITS);
/**
* 上次生成ID的时间截+毫秒内序列
*/
private final AtomicLongAndLong lastTimestampAndSerialNumber = new AtomicLongAndLong(-1L, 0L);
/**
* 工作机器ID
*/
@Getter
private final int workerId;
/**
* @param workerId 0~{@link SnowflakeIdUtils#MAX_WORKER_ID}
*/
public SnowflakeIdUtils(int workerId) {
if (workerId > MAX_WORKER_ID || workerId < 0) {
throw new IllegalArgumentException("workerId必须大于等于0小于等于" + MAX_WORKER_ID);
}
this.workerId = workerId;
}
/**
* 获得当前毫秒和毫秒内的自增序列
*
* @return [timestamp, serialNumber]
*/
public TimestampAndSerialNumber genTimestampAndSerialNumber() {
long thisSerialNumber;
//如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退
long timestamp;
long lastTime;
for (; ; ) {
lastTime = this.lastTimestampAndSerialNumber.getMain();
timestamp = this.timeGen();
while (timestamp < lastTime) {
long backTime = lastTime - timestamp;
//时钟回退很小
if (backTime < FALLBACK_ACCEPT_MILLISECONDS) {
try {
Thread.sleep(backTime);
} catch (InterruptedException ignored) {
}
if (this.timeGen() < this.lastTimestampAndSerialNumber.getMain()) {
throw new RuntimeException("时钟多次回退");
}
} else {
throw new RuntimeException("时钟回退,请重试");
}
lastTime = this.lastTimestampAndSerialNumber.getMain();
timestamp = this.timeGen();
}
//如果是同一时间生成的,则获取当前递增数字
if (lastTime == timestamp) {
long minor = thisSerialNumber = this.lastTimestampAndSerialNumber.getMinor();
if (!this.lastTimestampAndSerialNumber.compareAndSetMinor(timestamp, minor, minor + 1)) {
//已经下一个毫秒了,重试
continue;
}
//毫秒内序列溢出
if (thisSerialNumber >= SERIAL_NUMBER_MAX) {
//阻塞到下一个毫秒
this.waitUntilTheNextMillis(lastTime);
continue;
}
break;
} else {
//否则更新时间
if (this.lastTimestampAndSerialNumber.compareAndSetMain(lastTime, timestamp, 1L)) {
thisSerialNumber = 0L;
break;
}
}
}
return new TimestampAndSerialNumber(timestamp, thisSerialNumber);
}
/**
* 生成下一个雪花ID
*
* @return 唯一雪花id
*/
public long genId() {
TimestampAndSerialNumber timestampAndSerialNumber = this.genTimestampAndSerialNumber();
return numbers2Long(timestampAndSerialNumber.getTimestamp() - REFERENCE_TIME, TIMESTAMP_OFFSET, this.workerId,
WORKER_ID_OFFSET, timestampAndSerialNumber.getSerialNumber(), SERIAL_NUMBER_OFFSET);
}
/**
* 生成易识别的下一个雪花ID,目前会重复,不建议使用
*
* @return 唯一雪花id
*/
@Deprecated
public long genFormatId() {
TimestampAndSerialNumber t = this.genTimestampAndSerialNumber();
long l = numbers2Long(t.getTimestamp(), TIMESTAMP_OFFSET, this.workerId, WORKER_ID_OFFSET, t.getSerialNumber(),
SERIAL_NUMBER_OFFSET);
return Long.parseLong(
DateFormatUtils.format(new Date(t.timestamp), "yyMMddHHmm") + String.valueOf(l).substring(10, 19));
}
/**
* 生成易识别的下一个雪花ID,不会重复
*
* @return 唯一雪花id
*/
public String genFormatIdStr() {
TimestampAndSerialNumber t = this.genTimestampAndSerialNumber();
String l = String.valueOf(numbers2Long(this.workerId, WORKER_ID_OFFSET, t.getSerialNumber(),
SERIAL_NUMBER_OFFSET));
return DateFormatUtils.format(new Date(t.timestamp), "yyMMddHHmmssSSS") + StringUtils
.repeat("0", 8 - l.length()) + l;
}
/**
* 拼接多个数字为一个数
*
* @return
*/
public static long numbers2Long(long number1, int offset1, long number2, int offset2) {
return (number1 << offset1) | (number2 << offset2);
}
/**
* 拼接多个数字为一个数
*
* @return
*/
public static long numbers2Long(long number1, int offset1, long number2, int offset2, long number3, int offset3) {
return ((number1 << offset1) | (number2 << offset2)) | (number3 << offset3);
}
/**
* 拼接多个数字为一个数
*
* @return
*/
public static long numbers2Long(long number1, int offset1, long number2, int offset2, long number3, int offset3,
long number4, int offset4) {
return (((number1 << offset1) | (number2 << offset2)) | (number3 << offset3)) | (number4 << offset4);
}
/**
* 阻塞到下一毫秒
*
* @param lastTimestamp 当前的毫秒数
*/
protected void waitUntilTheNextMillis(long lastTimestamp) {
long timestamp = this.timeGen();
for (int i = 0; timestamp == lastTimestamp; i++) {
if (i > 10) {
Thread.yield();
}
timestamp = this.timeGen();
}
}
/**
* 返回当前时间
*
* @return 当前时间(毫秒)
*/
public long timeGen() {
return System.currentTimeMillis();
}
int testGenId(boolean statisticalDuplication, int mode, int threadsNumber, long everyThreadGeneratedQuantity)
throws InterruptedException {
Thread[] threads = new Thread[threadsNumber];
ConcurrentLinkedDeque<Object> list = new ConcurrentLinkedDeque<>();
LongAdder count = new LongAdder();
CountDownLatch latch = new CountDownLatch(threads.length + 1);
Random random = new Random();
ConcurrentSkipListSet<Integer> ids = new ConcurrentSkipListSet<>();
Runnable runnable = () -> {
int workerId;
do {
workerId = random.nextInt(MAX_WORKER_ID);
if (!ids.contains(workerId)) {
ids.add(workerId);
break;
}
} while (true);
SnowflakeIdUtils snowflakeIdUtils =
// this;
new SnowflakeIdUtils(workerId);
for (int i1 = 0; i1 < everyThreadGeneratedQuantity; i1++) {
count.add(1);
Object key;
if (mode == 0) {
key = snowflakeIdUtils.genId();
} else if (mode == 1) {
key = snowflakeIdUtils.genFormatId();
} else {
key = snowflakeIdUtils.genFormatIdStr();
}
if (statisticalDuplication) {
list.add(key);
}
}
latch.countDown();
};
Thread thread1 = new Thread(runnable);
thread1.start();
thread1.join();
ids.clear();
list.clear();
count.reset();
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(runnable, "gen-" + i);
}
long startTime = System.currentTimeMillis();
for (Thread thread : threads) {
thread.start();
}
latch.await();
HashSet<Object> set = new HashSet<>(list.size() / 10);
int res = 0;
if (statisticalDuplication) {
int num = 0;
for (Object o : list) {
if (set.contains(o)) {
num++;
} else {
set.add(o);
}
}
res += num;
}
return res;
}
static Map<String, Object> decode(long id) {
HashMap<String, Object> res = new HashMap<>();
long timestamp = (id >>> TIMESTAMP_OFFSET)
& (((-1L << (Long.SIZE - TIMESTAMP_BITS))
>>> (Long.SIZE - TIMESTAMP_BITS))
);
res.put("TIMESTAMP", timestamp + REFERENCE_TIME);
res.put("TIMESTAMP_ORIGINAL", timestamp);
res.put("DATA", new Date(timestamp + REFERENCE_TIME).toLocaleString());
res.put("WORKER_ID", (((id >>> WORKER_ID_OFFSET)
& (((-1L << (Long.SIZE - WORKER_ID_BITS))
>>> (Long.SIZE - WORKER_ID_BITS))
))));
res.put("SERIAL_NUMBER", ((id >>> SERIAL_NUMBER_OFFSET)
& (
((-1L << (Long.SIZE - SERIAL_NUMBER_BITS))
>>> (Long.SIZE - SERIAL_NUMBER_BITS))
)
));
return res;
}
@Override
public String toString() {
return "SnowflakeIdUtils{"
+ "workerId=" + this.workerId
+ '}';
}
@Data
public static class TimestampAndSerialNumber {
private final long timestamp;
private final long serialNumber;
}
}
以实战来学习java,希望每个从我这边都有收获,有需要的同学加扣扣群:646410846,一起学习,共同进步~