使用 Java 7 或 Java 6 生成随机 UUID 的性能无争用与争用

2022-09-02 14:21:52

我有一个基于Web的Java应用程序,它为会话信息生成随机UUID。我们的一位测试人员声称根据他自己的分析生成UUID长达350毫秒,但我还没有能够复制他的结果。他指出这篇文章 http://www.cowtowncoder.com/blog/archives/2010/10/entry_429.html 来帮助支持他的结果。我想看看是否有其他人在Java 6或Java 7应用程序中使用Java内置的UUID生成功能遇到了这种限制。


答案 1

下面是在 beta 127 中运行的测试。

请记住,这个测试是不现实的,超出了我能想象到的任何最坏情况。我的目标是让那些恶语相传的人安静下来,而事实却没有事实来支持他们的批评。

场景:

  • java.util.UUID.randomUUID() 的一百万次调用的紧密循环
    • 一个测试,仅凭这一点。(无争用)
    • 一个具有争用的测试,其中其他 2 个线程处于紧密循环中,进行 1000 万次调用。
  • Java 8 beta 127
    • java 版本 “1.8.0”
    • Java(TM) SE Runtime Environment (build 1.8.0-b127)
    • Java HotSpot(TM) 64 位服务器虚拟机(内部版本 25.0-b69,混合模式)
  • 从 Netbeans 7.4 IDE 运行
  • 在虚拟机内执行
  • Mac mini (2012 年末)

无争用

在一个线程中运行一个循环,因此不会争用同步的方法/类。

// Warm the random generator.
java.util.UUID uuid;
uuid = java.util.UUID.randomUUID();

long stop = 0;
long start = System.nanoTime();

int loops = 1000000;  // One million.
for ( int i = 0; i < loops; i++ ) {
    uuid = java.util.UUID.randomUUID();
}

stop = System.nanoTime();

long elapsed = ( stop - start );

System.out.println( "UUIDs: " + loops );
System.out.println( "Nanos: " + elapsed );
System.out.println( "Nanos per uuid: " + ( elapsed / loops ) + " ( micros per: " + ( elapsed / loops / 1000 ) + " )" );

结果

每个 UUID 大约 2 微秒

与争用

与上面类似,但是在执行一百万个调用的循环时,我们还有另外两个线程在运行,每个线程进行一千万次调用。

// Warm the random generator.
java.util.UUID uuid;
uuid = java.util.UUID.randomUUID();

int pass = 10_000_000 ;  // Ten million.
MyThread t1 = new MyThread( pass );
MyThread t2 = new MyThread( pass );


t1.start();
t2.start();
t3.start();

long stop = 0;
long start = System.nanoTime();

int loops = 1_000_000 ;  // One million.
for ( int i = 0; i < loops; i++ ) {
    uuid = java.util.UUID.randomUUID();
}

stop = System.nanoTime();

long elapsed = ( stop - start );

System.out.println( "UUIDs: " + loops );
System.out.println( "Nanos: " + elapsed );
System.out.println( "Nanos per uuid: " + ( elapsed / loops ) + " ( micros per: " + ( elapsed / loops / 1000 ) + " )" );

定义每个线程的类...

class MyThread extends Thread {

    private int loops;

    public MyThread( int loops ) {
        this.loops = loops;
    }

    @Override
    public void run() {
        java.util.UUID uuid;
        for ( int i = 0; i < this.loops; i++ ) {
            uuid = java.util.UUID.randomUUID();
        }

    }
}

结果

每个 UUID 大约 20 微秒

运行次数为每 UUID 14、20、20、23 和 24 微秒(不按此顺序)。因此,在极端的争论下,情况只差了大约10倍,在我所知道的任何现实世界中,20微秒是可以接受的。


答案 2

我测试了它

    for (;;) {
        long t0 = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            UUID.randomUUID();
        }
        System.out.println(System.currentTimeMillis() - t0);
    }

在我的PC上,它是〜1100毫秒,这是相当慢的。UUID.randomUUID() 在内部使用 SecureRandom,为了更快,我们可以使用常规的 java.util.Random

    Random r = new Random();
    for (;;) {
            ..
            new UUID(r.nextLong(), r.nextLong());

它约为 80 毫秒