Java 使ULID词典排序对时间更敏感

Java 使ULID词典排序对时间更敏感,java,uuid,uid,Java,Uuid,Uid,我曾在一个项目中使用过,在这个项目中,我不仅需要ULID提供的唯一性,还需要它的词典排序能力 然而,我发现,无论我做了多少尝试,我都无法在循环中对生成的ID进行排序 e、 g 这对我的工作来说还不够好。。。我不想等待任何时间来生成ulid(即使是10us-100us),人工延迟的概念让我非常困扰,哈哈 因此,我修改了ULID.java并将时间源从System.currentTimeMillis()更改为System.nanoTime() 令我惊讶的是,我不再需要在循环中使用任何时间延迟来获得可排

我曾在一个项目中使用过,在这个项目中,我不仅需要ULID提供的唯一性,还需要它的词典排序能力

然而,我发现,无论我做了多少尝试,我都无法在循环中对生成的ID进行排序

e、 g

这对我的工作来说还不够好。。。我不想等待任何时间来生成ulid(即使是10us-100us),人工延迟的概念让我非常困扰,哈哈

因此,我修改了ULID.java并将时间源从
System.currentTimeMillis()
更改为
System.nanoTime()

令我惊讶的是,我不再需要在循环中使用任何时间延迟来获得可排序的输出ulid

我觉得一定有什么地方出了问题;因为Java规范警告说,
System.nanoTime()
不一定比
System.currentTimeMillis()更准确

e、 g在
System.nanoTime()
的Javadoc中,它说:

此方法提供纳秒精度,但不一定是纳秒分辨率(即值变化的频率)-除分辨率至少与currentTimeMillis()的分辨率一样好外,不作任何保证。

另外,
System.nanoTime()
的Javadoc似乎表明它与历元无关(正如
System.currentTimeMillis()

我相信这可能会导致在ULID.java中使用
System.nanoTime()
而不是
System.currentTimeMillis()

问题

  • 我的恐惧是合理的吗
  • 如果(1.)是真的,我能做什么来提高ULID的时间敏感度超过1毫秒而不破坏其优点

  • ULID有两个部分:时间部分和随机部分

    时间分量是自1970年以来的毫秒计数

    随机组件在两种情况下更新:

  • 当毫秒变化时,产生一个新的随机值
  • 当毫秒相同时,随机值增加1
  • 这里显示的实现不执行第二步

    也许您可以包含如下代码(只是一个示例):

    if(timestamp==previousTimestamp){
    随机组件++;
    }否则{
    randomComponent=RANDOM.nextLong();
    }
    
    我发现的另一个问题是它使用Math.random(),而不是
    java.security.SecureRandom
    。要解决此问题,请执行以下建议:

    导入java.security.SecureRandom;
    私有静态最终随机=新SecureRandom();
    
    最后,不建议使用
    System.nanoTime()
    ,因为它返回自任意时间点以来的纳秒数。这不是从主板上的实时时钟(RTC)返回的白天时间。此函数用于测量代码中两点之间的运行时间,可能用于基准测试。例如:

    
    long startNanos=System.nanoTime();
    //在这里做一些昂贵的工作
    long-endNanos=System.nanoTime();
    long elapsedNanos=endNanos-startNanos;
    
    如果愿意,可以查看库
    ulid creator
    。也许会有帮助。例如:

    //将ULID生成为UUID
    UUID ulid=UlidCreator.getUlid();
    //或者生成一个ULID作为字符串(Crockford的base32)
    字符串ulid=UlidCreator.getUlidString();
    
    项目页面:

    编辑

    对不起。我没有回答这些问题

    我的恐惧是合理的吗

    是的,你的赖特

    如果(1.)为真,我该怎么办才能将ULID的时间敏感度提高到1毫秒以上而不破坏其优点?

    您可以提高ULID分辨率,但它不符合标准(顺便说一句,这不是RFC-4122那样的正式标准)。由此产生的UUID类似于Jimmy Wilson创建的。两者的主要思想是相同的

    您可以为时间戳组件保留更多位,但它会有一些位的开销。例如,如果将时间分量从48位增加到64位,它将在公元2262年前后滚动,但随机分量将从1208925819614629174706176(2^80)减少到18446744073709551616(2^64)。如果成本影响ULID的优点,则取决于您的项目


    我刚刚为ULID实现了一个纳秒分辨率的生成器。几天前我碰巧正在做这件事。使用方法
    System.currentTimeMillis()
    ,它实际上具有毫秒精度。在两次后续调用之间,使用方法
    System.nanoTime()
    模拟纳秒级结果

    如果您仍打算使用纳秒ULID,请随时进行测试:

    打包您的.package.name;
    导入java.security.SecureRandom;
    导入java.time.Instant;
    导入java.util.UUID;
    /**
    *创建具有纳秒分辨率的梳状GUID的实用程序类。
    * 
    *它借用了ULID和COMB生成器的主要思想:将
    *时间和随机字节。它由64位表示时间,64位表示随机
    *点点滴滴。
    * 
    *纳米梳有两个组件:
    * 
    * 1. 时间单位(64位):自1970年以来的纳秒
    * 
    * 2. 随机分量(64位):由安全随机变量生成的值
    *发电机。
    * 
    *最长时间成分年为公元2262年(2^63/10^9/60/60/24/365.25+1970年)
    * 
    *@作者:法比奥·利马2020
    */
    公共期末班{
    私有长时间=0;
    私有长prevNano=0;
    私有静态最终长100万纳秒=1 000升;
    private static final SecureRandom SECURE_RANDOM=new SecureRandom();
    /**
    *返回以纳秒为单位的时间分量。
    * 
    *它使用'System.currentTimeMillis()'以毫秒为单位获取系统时间
    *精度。纳秒分辨率是通过调用
    
    class Test{
        public static void main(String[] args) {
                ArrayList<String> ulids = new ArrayList<>();
        
                for (int i = 0; i < 10; i++) {
                   
                    ulids.add(ULID.generate());
                }
        
                System.out.println("Original:\n..." + ulids);
        
                Collections.shuffle(ulids);
        
                System.out.println("Shuffled:\n..." + ulids);
        
                ulids.sort(new Comparator<String>() {
                    @Override
                    public int compare(String o1, String o2) {
                        return o1.compareTo(o2);
                    }
                });
        
                System.out.println("Sorted:\n..." + ulids);
        
            }
    }
    
    Sample output:
    Original:
    ...[01edrp4ng81d3mvkp8s7z19znm, 01edrp4ng872nwfj6b9fsxjkkd, 01edrp4ng86v07r6c9sh62ghr7, 01edrp4ng8bpfw3m2q8bynd5st, 01edrp4ng896t1qhsngrz3h251, 01edrp4ng8jne084nsw5saesfe, 01edrp4ng8w8qz9qtgy3958r1v, 01edrp4ng8fdn30qnr2ktddyz4, 01edrp4ng8ekj0vt393tw12x8j, 01edrp4ng80wacxxskgej5d8mm]
    Shuffled:
    ...[01edrp4ng896t1qhsngrz3h251, 01edrp4ng8w8qz9qtgy3958r1v, 01edrp4ng86v07r6c9sh62ghr7, 01edrp4ng8bpfw3m2q8bynd5st, 01edrp4ng8fdn30qnr2ktddyz4, 01edrp4ng80wacxxskgej5d8mm, 01edrp4ng872nwfj6b9fsxjkkd, 01edrp4ng81d3mvkp8s7z19znm, 01edrp4ng8jne084nsw5saesfe, 01edrp4ng8ekj0vt393tw12x8j]
    Sorted:
    ...[01edrp4ng80wacxxskgej5d8mm, 01edrp4ng81d3mvkp8s7z19znm, 01edrp4ng86v07r6c9sh62ghr7, 01edrp4ng872nwfj6b9fsxjkkd, 01edrp4ng896t1qhsngrz3h251, 01edrp4ng8bpfw3m2q8bynd5st, 01edrp4ng8ekj0vt393tw12x8j, 01edrp4ng8fdn30qnr2ktddyz4, 01edrp4ng8jne084nsw5saesfe, 01edrp4ng8w8qz9qtgy3958r1v]
    
    class TestWithMsDelay{
    
       public static void main(String[] args) {
            ArrayList<String> ulids = new ArrayList<>();
    
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(5L);
                    ulids.add(ULID.generate());
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
    
            System.out.println("Original:\n..." + ulids);
    
            Collections.shuffle(ulids);
    
            System.out.println("Shuffled:\n..." + ulids);
    
            ulids.sort(new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    return o1.compareTo(o2);
                }
            });
    
            System.out.println("Sorted:\n..." + ulids);
    
        }
    
    
    }
    Sample output:
    Original:
    ...[2rjdme5a5h2ntcd20xq4z487tx, 2rjdme63a23ddsy0km21n6n34a, 2rjdme6pnrenx79zd3jj18est4, 2rjdme70bv45b648p82dbj584n, 2rjdme7d8gx9v9db66ftsxbmqq, 2rjdme7psqdykt24qfymn2e4ba, 2rjdme80as7t1h1rr00m676718, 2rjdme8rztp50bad6ktkhrfhk8, 2rjdme93ngkxkfmf6aegqxer9e, 2rjdme9ea04x22rpx2f3rp5gez]
    Shuffled:
    ...[2rjdme7psqdykt24qfymn2e4ba, 2rjdme6pnrenx79zd3jj18est4, 2rjdme80as7t1h1rr00m676718, 2rjdme63a23ddsy0km21n6n34a, 2rjdme93ngkxkfmf6aegqxer9e, 2rjdme70bv45b648p82dbj584n, 2rjdme9ea04x22rpx2f3rp5gez, 2rjdme8rztp50bad6ktkhrfhk8, 2rjdme7d8gx9v9db66ftsxbmqq, 2rjdme5a5h2ntcd20xq4z487tx]
    Sorted:
    ...[2rjdme5a5h2ntcd20xq4z487tx, 2rjdme63a23ddsy0km21n6n34a, 2rjdme6pnrenx79zd3jj18est4, 2rjdme70bv45b648p82dbj584n, 2rjdme7d8gx9v9db66ftsxbmqq, 2rjdme7psqdykt24qfymn2e4ba, 2rjdme80as7t1h1rr00m676718, 2rjdme8rztp50bad6ktkhrfhk8, 2rjdme93ngkxkfmf6aegqxer9e, 2rjdme9ea04x22rpx2f3rp5gez]
    
    OUTPUT:
    
    UUID: '16240ee8-3865-1503-d1fb-b4e85f991c6b', time: 2020-07-22T11:15:58.537327680Z
    UUID: '16240ee8-3865-f90a-ca19-3ec529750ef7', time: 2020-07-22T11:15:58.537344064Z
    UUID: '16240ee8-3866-dd7c-f32f-7acaebcf7766', time: 2020-07-22T11:15:58.537409664Z
    UUID: '16240ee8-3868-0a99-3ead-b114e1d61520', time: 2020-07-22T11:15:58.537524800Z
    UUID: '16240ee8-3868-efc8-937d-599c72de71a6', time: 2020-07-22T11:15:58.537541248Z
    UUID: '16240ee8-386a-3643-6a5e-e3b5e3b03c71', time: 2020-07-22T11:15:58.537655936Z
    UUID: '16240ee8-386b-132f-7016-057ab30a2920', time: 2020-07-22T11:15:58.537721408Z
    UUID: '16240ee8-386b-f929-d5b0-f70b68aea3d9', time: 2020-07-22T11:15:58.537737280Z