Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snowflake生成器单机模拟时间回退导致id重复 #1206

Closed
nickszeng opened this issue Nov 6, 2020 · 6 comments
Closed

Snowflake生成器单机模拟时间回退导致id重复 #1206

nickszeng opened this issue Nov 6, 2020 · 6 comments
Labels

Comments

@nickszeng
Copy link

nickszeng commented Nov 6, 2020

版本情况

JDK版本: 1.8
hutool版本: 5.4.2
操作系统:window

问题描述(包括截图)

  1. 复现代码
    复制cn.hutool.core.lang.Snowflake
public class Snowflake implements Serializable {

	private Random random = new Random();
        //修改获取操作系统时间 随机时间回退0-100ms
	private long genTime() {
		return this.useSystemClock ? SystemClock.now() : System.currentTimeMillis() - random.nextInt(2) * 100;
	}
}

测试main方法

    public static void main(String[] args) {
        Set<Long> ids = new HashSet<>();
       //使用操作系统时间
        Snowflake1 snowflake1 = new Snowflake1(1, 1, false);
        for (; ; ) {
            try {
                long id = snowflake1.nextId();
                if (!ids.add(id)) {
                    System.err.println("发生重复ID:" + id);
               }
            } catch (Exception e) {
                //
            }
        }
    }
  1. 堆栈信息

  2. 测试涉及到的文件(注意脱密)
    image

4.正确输出
a: 当注释掉2s容忍时间回拨后未出现重复现象
image

b: 当不使用操作系统时间时候未出现重复现象

Snowflake1 snowflake1 = new Snowflake1(1, 1, true); //使用SystemClock

5.疑惑
image
其实按上图来看,nextId方法当发生时间回拨后是有做处理的,也就是前一次时间未打满情况会强制等待时间前行, 这也是我思想向后未想出为啥会出现重复的原因,还请作者帮忙解答下。

@looly looly added the bug label Nov 10, 2020
@looly
Copy link
Member

looly commented Nov 10, 2020

确实有问题,问题出在:

在时间回退后,就算报错ID也会一直在不停增长,因为ID最大是4096,导致增长到最大后归零了。

5.5.0修复此问题,感谢!

@looly looly closed this as completed Nov 10, 2020
@ShepherdZFJ
Copy link

确实有问题,问题出在:

在时间回退后,就算报错ID也会一直在不停增长,因为ID最大是4096,导致增长到最大后归零了。

5.5.0修复此问题,感谢!

请问一下该问题是怎么解决修复的呀?我在5.7.20版本看源码逻辑还是一样的呀

@looly
Copy link
Member

looly commented Aug 9, 2022

@ShepherdZFJ 升级5.8.5试下。

@ShepherdZFJ
Copy link

确实有问题,问题出在:
在时间回退后,就算报错ID也会一直在不停增长,因为ID最大是4096,导致增长到最大后归零了。
5.5.0修复此问题,感谢!

请问一下该问题是怎么解决修复的呀?我在5.7.20版本看源码逻辑还是一样的呀

不好意思

确实有问题,问题出在:

在时间回退后,就算报错ID也会一直在不停增长,因为ID最大是4096,导致增长到最大后归零了。

5.5.0修复此问题,感谢!

不好意思,看到源码改动了,起了一个局部变量 final long sequence = (this.sequence + 1) & SEQUENCE_MASK;

@ShepherdZFJ 升级5.8.5试下。

好的,已解决了,多谢了

@nyingping
Copy link

生产环境上遇到这个问题了

@looly
Copy link
Member

looly commented Sep 4, 2022

@nyingping 麻烦升级到最新版本的hutool,然后使用getSnowflake单例使用。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants