【问题标题】:java for loop executes too fast gives System.currentTimeMillis() duplicatejava for 循环执行太快导致 System.currentTimeMillis() 重复
【发布时间】:2011-09-22 03:46:48
【问题描述】:

Java:我在使用 System.currentTimeMillis() 函数时遇到问题

我正在使用 System.currentTimeMillis() 在 foo 循环中生成唯一值,问题是循环执行速度太快,而 System.currentTimeMillis() 给了我重复的值。

如何生成确定的唯一值。

for(int a=0;a<=10;a++){
System.out.println(System.currentTimeMillis())
}

我也尝试过关注,但也不是生成唯一编号

System.currentTimeMillis()+Math.random()

【问题讨论】:

    标签: java random for-loop unique


    【解决方案1】:

    我的建议

        long id = System.currentTimeMillis();
        for (int i = 0; i < 10; i++) {
            //do your work
            id++;
        }
    

    【讨论】:

    • 如果它是一个建议评论它,如果它是一个答案请保留在这里
    【解决方案2】:

    答案很明显——买一台速度较慢的电脑!好吧,或者使用 SO-System.currentTimeMillis vs System.nanoTime 上描述的 System.nanoTime。但说真的,除非万不得已,否则不应将时间用作唯一数字生成器。

    使用系统时间的问题当然是:

    • 系统返回的时间 电话被四舍五入到更高的 精度高于实际 CPU 时钟时间。如果您的 ID 生成 代码运行速度超过这个程度 精度,那么您将拥有 碰撞。
    • 如果您的代码是分布式的并且每个 然后工作单元生成 ID 你遇到了身份证的可能性 碰撞作为单独的 CPU 或 CPU 内核的分配 ID 使用它们的 独立时钟。
    • 在像 Java 这样的库中 实际返回系统时间 基于用户可设置的属性 你遇到更高的机会 多个ID冲突随时 日期被重置为某个时期 过去,无论出于何种原因。

    生成唯一标识符的一个很好的替代方法是使用不那么讽刺的名称Universally Unique Identifier。有多种语言的多种实现,对于 Java 5 及更高版本,您可以使用 UUID 类。

    编辑:添加一些关于 UUID 的有用信息。

    【讨论】:

    • +1 表示“除非万不得已,否则不应将时间用作唯一数字生成器。”
    • +1 没错,最好使用更强大的算法来生成唯一值。例如,如果应用程序在多台计算机上运行,​​每台计算机都生成自己的值怎么办?
    • +1 使用 UUID、静态计数器(单个 JVM)或集群单例计数器(数据库或花哨的集群单例)。
    【解决方案3】:

    类似于@Andrej 的解决方案,但结合了计时器和计数器,因此如果您重新启动应用程序,您的数字不应重复。

    public enum IdGenerator {
        ;
    
        private static final AtomicLong COUNTER = new AtomicLong(System.currentTimeMillis()*1000);
    
        public static long nextId() { return COUNTER.getAndIncrement(); }
    }
    

    【讨论】:

      【解决方案4】:

      也请查看UUID...

      【讨论】:

        【解决方案5】:

        试试 Math.random()*System.currentTimeMillis()

        这是一个示例结果

        4.1140390961236145E11,
        4.405289623285403E11,
        6.743938910583776E11,
        2.0358542930175632E11,
        1.2561886548511025E12,
        8.629388909268735E11,
        1.158038719369676E12,
        2.5899667030405692E11,
        7.815373208372445E11,
        1.0887553507952611E12,
        3.947241572203385E11,
        1.6723200316764807E11,
        1.3071550541162832E12,
        2.079941126415029E11,
        1.304485187296599E12,
        3.5889095083604164E10,
        1.3230275106525027E11,
        6.484641777434403E11,
        5.109822261418748E11,
        1.2291750972884333E12,
        8.972865957307518E11,
        4.022754883048088E11,
        7.997154244301389E11,
        1.139245696210086E12,
        2.633248409945871E11,
        8.699957189419155E11,
        9.487098785390422E11,
        1.1645067228773708E12,
        1.5274939161218903E11,
        4.8470112347655725E11,
        8.749120668472205E11,
        2.435762445513599E11,
        5.62884487469596E11,
        1.1412787212758718E12,
        1.0724213377031631E12,
        3.1388106597100226E11,
        1.1405727247661633E12,
        1.2464739913912961E12,
        3.2771161059896655E11,
        1.2102869787179648E12,
        1.168806596179512E12,
        5.871383012375131E11,
        1.2765757372075571E12,
        5.868323434343102E11,
        9.887351363037219E11,
        5.392282944314777E11,
        1.1926033895638833E12,
        6.867917070018711E11,
        1.1682059242674294E12,
        2.4442056772643954E11,
        1.1250254537683052E12,
        8.875186600355891E10,
        3.46331811747409E11,
        1.127077925657995E12,
        7.056541627184794E11,
        1.308631075052609E12,
        7.7875319089675E11,
        5.52717019956371E11,
        7.727797813063546E11,
        6.177219592063667E11,
        2.9448141585070874E11,
        9.617992263836586E11,
        6.762500987418107E11,
        1.1954995292124463E12,
        1.0741763597148225E12,
        1.9915919731861673E11,
        9.507720563185525E11,
        1.1009594810160002E12,
        4.1381256571745465E11,
        2.2526550777831213E11,
        2.5919816802026202E11,
        3.8453225321522577E11,
        3.796715779825083E11,
        6.512277843921505E10,
        1.0483456960599313E12,
        1.0725956186588704E11,
        5.701504883615902E11,
        9.085583903150035E11,
        1.2764816439306753E12,
        1.033783414053437E12,
        1.188379914238302E12,
        6.42733442524156E11,
        3.911345432964901E11,
        7.936334657654698E11,
        1.4473479058272617E11,
        1.2030471387183499E12,
        5.900668555531211E11,
        8.078992189613184E11,
        1.2004364275316113E12,
        1.250275098717202E12,
        2.856556784847933E11,
        1.9118298791320355E11,
        5.4291847597892596E11,
        3.9527733898520874E11,
        6.384539941791654E11,
        1.2812873515441786E11,
        6.325269269733575E9,
        5.403119000792323E11,
        8.023708335126083E11,
        3.761680594623883E10,
        1.2641772837928888E11,
        

        【讨论】:

        • 那么为什么不使用 Math.random() 如果你只需要一个唯一的数字呢?时间的概念已经消失,所以你所拥有的只是(希望)唯一的数字。
        • 基础数学:随机数列与唯一数列不同。乘以系统时间可能会稍微改变分布,但仍然不是唯一的。
        【解决方案6】:

        如果你还想继续使用你的方法,你可以这样做:

        for(int a=0;a<=10;a++){
            Thread.sleep(1);
            System.out.println(System.currentTimeMillis())
        }
        

        显式降低 CPU 速度。

        【讨论】:

          【解决方案7】:

          如果这是一个要求,我认为你的方法是错误的。

          理论上,无论您的计时器有多细粒度,一台机器可能在比计时器的粒度更短的时间内执行它。从技术意义上说,依赖这是真的是不正确的。

          或者换个角度看 - 为什么你需要这些值是唯一的(你用它们做什么)?如果您真的希望它们成为执行时间的度量,那么您应该很高兴在同一毫秒内发生的两次迭代得到相同的值。

          您是否考虑过使用静态、单调的计数器来为每次迭代分配在每次执行中唯一的 ID(AtomicLong 非常适合此操作)?像下面这样的东西非常简单,没有并发问题:

          public class YourClass {
          
              private static final AtomicLong COUNTER = new AtomicLong();
          
              private static nextId() { return COUNTER.getAndIncrement(); }
          
              // Rest of the class, which calls nextId() when it needs an identifier
          }
          

          如果您需要时间信息唯一性,那么这是两个独立的要求,那么为什么不使用由时间任意唯一ID组成的复合键呢?

          【讨论】:

          • 是的,方法是错误的。随机数和系统时间都不能保证唯一的数字。这里的静态计数器适用于单 JVM 系统。它不会在集群中工作。
          【解决方案8】:

          为什么不使用 UUID 库来生成唯一标识符(JDK http://download.oracle.com/javase/6/docs/api/java/util/UUID.html 中已经存在)。

          或者更简单的方法:附加一个静态计数器

          【讨论】:

            【解决方案9】:

            你为什么不改用System.nanoTime()

            【讨论】:

            • 如果我在更快的机器上执行更多,是否有机会使其重复值?
            • 来自 JavaDoc:“不保证值更改的频率。”您可以轻松遇到一个不会比currentTimeMillis()更频繁地更改的实现。
            • 我同意@Perception 的观点,即您不应该使用系统计时器来生成唯一编号:即使您的系统速度慢到无法在每次迭代中生成相同的 ID,但如果您运行它会发生什么在多处理器架构上,其中 2 个线程可以同时同时运行并以相同的 id 结束。不如改用这样的东西:javapractices.com/topic/TopicAction.do?Id=56
            • @Faisal 我得到重复值
            • 我同意如果专门在循环中比较我们不应该喜欢这个想法有随机 UUID
            猜你喜欢
            • 2021-02-13
            • 1970-01-01
            • 2012-01-07
            • 2014-10-07
            • 1970-01-01
            • 1970-01-01
            • 2019-05-28
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多