diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/data/id/Snowflake.java b/hutool-core/src/main/java/org/dromara/hutool/core/data/id/Snowflake.java index 229674b20..7ab196978 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/data/id/Snowflake.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/data/id/Snowflake.java @@ -15,7 +15,6 @@ package org.dromara.hutool.core.data.id; import org.dromara.hutool.core.date.SystemClock; import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.tuple.Pair; -import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.util.RandomUtil; import java.io.Serializable; @@ -53,11 +52,6 @@ public class Snowflake implements Serializable { * 默认的起始时间,为Thu, 04 Nov 2010 01:42:54 GMT */ public static long DEFAULT_TWEPOCH = 1288834974657L; - /** - * 默认回拨时间,2S - */ - public static long DEFAULT_TIME_OFFSET = 2000L; - private static final long WORKER_ID_BITS = 5L; // 最大支持机器节点数0~31,一共32个 @SuppressWarnings({"PointlessBitwiseExpression", "FieldCanBeLocal"}) @@ -84,10 +78,6 @@ public class Snowflake implements Serializable { private final long workerId; private final long dataCenterId; private final boolean useSystemClock; - /** - * 允许的时钟回拨毫秒数 - */ - private final long timeOffset; /** * 当在低频模式下时,序号始终为0,导致生成ID始终为偶数
* 此属性用于限定一个随机上限,在不同毫秒下生成序号时,给定一个随机数,避免偶数问题。
@@ -146,20 +136,9 @@ public class Snowflake implements Serializable { * @param isUseSystemClock 是否使用{@link SystemClock} 获取当前时间戳 * @since 5.1.3 */ - public Snowflake(final Date epochDate, final long workerId, final long dataCenterId, final boolean isUseSystemClock) { - this(epochDate, workerId, dataCenterId, isUseSystemClock, DEFAULT_TIME_OFFSET); - } - - /** - * @param epochDate 初始化时间起点(null表示默认起始日期),后期修改会导致id重复,如果要修改连workerId dataCenterId,慎用 - * @param workerId 工作机器节点id - * @param dataCenterId 数据中心id - * @param isUseSystemClock 是否使用{@link SystemClock} 获取当前时间戳 - * @param timeOffset 允许时间回拨的毫秒数 - * @since 5.8.0 - */ - public Snowflake(final Date epochDate, final long workerId, final long dataCenterId, final boolean isUseSystemClock, final long timeOffset) { - this(epochDate, workerId, dataCenterId, isUseSystemClock, timeOffset, 0); + public Snowflake(final Date epochDate, final long workerId, final long dataCenterId, + final boolean isUseSystemClock) { + this(epochDate, workerId, dataCenterId, isUseSystemClock, 0); } /** @@ -167,17 +146,15 @@ public class Snowflake implements Serializable { * @param workerId 工作机器节点id * @param dataCenterId 数据中心id * @param isUseSystemClock 是否使用{@link SystemClock} 获取当前时间戳 - * @param timeOffset 允许时间回拨的毫秒数 * @param randomSequenceLimit 限定一个随机上限,在不同毫秒下生成序号时,给定一个随机数,避免偶数问题,0表示无随机,上限不包括值本身。 * @since 5.8.0 */ public Snowflake(final Date epochDate, final long workerId, final long dataCenterId, - final boolean isUseSystemClock, final long timeOffset, final long randomSequenceLimit) { + final boolean isUseSystemClock, final long randomSequenceLimit) { this.twepoch = (null != epochDate) ? epochDate.getTime() : DEFAULT_TWEPOCH; this.workerId = Assert.checkBetween(workerId, 0, MAX_WORKER_ID); this.dataCenterId = Assert.checkBetween(dataCenterId, 0, MAX_DATA_CENTER_ID); this.useSystemClock = isUseSystemClock; - this.timeOffset = timeOffset; this.randomSequenceLimit = Assert.checkBetween(randomSequenceLimit, 0, SEQUENCE_MASK); } @@ -219,19 +196,16 @@ public class Snowflake implements Serializable { public synchronized long nextId() { long timestamp = genTime(); if (timestamp < this.lastTimestamp) { - if (this.lastTimestamp - timestamp < timeOffset) { - // 容忍指定的回拨,避免NTP校时造成的异常 - timestamp = lastTimestamp; - } else { - // 如果服务器时间有问题(时钟后退) 报错。 - throw new IllegalStateException(StrUtil.format("Clock moved backwards. Refusing to generate id for {}ms", lastTimestamp - timestamp)); - } + timestamp = lastTimestamp; } if (timestamp == this.lastTimestamp) { + // 时间出现回拨,递增序号 final long sequence = (this.sequence + 1) & SEQUENCE_MASK; if (sequence == 0) { - timestamp = tilNextMillis(lastTimestamp); + // 如果序号耗尽,不再等待时间追赶,而是采用“超前消费”方式,让时间递增。 + // 这样可以避免系统暂停等待,而选择在“未来”ID新增不快时追上来。 + timestamp += 1; } this.sequence = sequence; } else { @@ -295,27 +269,6 @@ public class Snowflake implements Serializable { } // ------------------------------------------------------------------------------------------------------------------------------------ Private method start - - /** - * 循环等待下一个时间 - * - * @param lastTimestamp 上次记录的时间 - * @return 下一个时间 - */ - private long tilNextMillis(final long lastTimestamp) { - long timestamp = genTime(); - // 循环直到操作系统时间戳变化 - while (timestamp == lastTimestamp) { - timestamp = genTime(); - } - if (timestamp < lastTimestamp) { - // 如果发现新的时间戳比上次记录的时间戳数值小,说明操作系统时间发生了倒退,报错 - throw new IllegalStateException( - StrUtil.format("Clock moved backwards. Refusing to generate id for {}ms", lastTimestamp - timestamp)); - } - return timestamp; - } - /** * 生成时间戳 * diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/lang/SnowflakeTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/lang/SnowflakeTest.java index 23f0c99b6..1fb284f2e 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/lang/SnowflakeTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/lang/SnowflakeTest.java @@ -94,7 +94,7 @@ public class SnowflakeTest { @Disabled public void snowflakeRandomSequenceTest(){ final Snowflake snowflake = new Snowflake(null, 0, 0, - false, Snowflake.DEFAULT_TIME_OFFSET, 2); + false, 2); for (int i = 0; i < 1000; i++) { final long id = snowflake.nextId(); Console.log(id); @@ -107,7 +107,7 @@ public class SnowflakeTest { public void uniqueOfRandomSequenceTest(){ // 测试并发环境下生成ID是否重复 final Snowflake snowflake = new Snowflake(null, 0, 0, - false, Snowflake.DEFAULT_TIME_OFFSET, 100); + false, 100); final Set ids = new ConcurrentHashSet<>(); ThreadUtil.concurrencyTest(100, () -> {