在多线程应用程序中生成相同的 UUID

Same UUID being generated in multi-threaded application

我正在使用 UUID.randomUUID().toString() 将唯一值附加到最终存储在数据库中并对其具有唯一约束的字符串

但是因为我的应用程序是多线程的,所以执行是在 UUID 生成的同时发生的,最终相同的 UUID 被附加到字符串并且持久化失败。

是否有更好的方法来生成随机字符串,即故障安全方法。

我试过调试,当我暂停其他线程并让它们一个接一个地运行时,它工作正常。

我目前正在使用以下代码使其更加随机,但我不喜欢这种方法。

Random r = new Random();
List<Integer> uniqueNUmbers = new ArrayList<>();
for (int i=0;i<10;i++) {
int x=r.nextInt(9999);
while (uniqueNumbers.contains(x))
x=r.nextInt(9999);
uniqueNumbers.add(x);
} 
String string = String.format("%04d", uniqueNumbers.get(0));

string = uuid + string;

但这就像一个骇人听闻的代码。我不喜欢这样。

有没有人知道实际生成随机字符串的防故障方法。

您可以同步 uuid 生成方法,and/or您可以预生成 uuid 池并在池开始耗尽时在一个线程中生成更多标识符。

你可以试试这样的

int uuid = ThreadLocalRandom.current().nextInt());

也许这个例子可以帮助将来的人:

UUID uuid = UuidCreator.getRandomBased();

这个库使用 java.security.SecureRandom:

https://github.com/f4b6a3/uuid-creator

我看到了同样的事情。我在 multi-threaded 应用程序中调用 UUID.randomUUID()。不同的线程获得相同的 UUID。对我来说(我猜你),这是因为我将 uuid 存储在一个静态变量中:

  static class UserJourneyThread implements Callable<UserJourneyResult> {

    private static final String uuid = UUID.randomUUID().toString();

    public UserJourneyResult call() {
    }
  }

如果每个线程调用一次 call(),这应该可以解决问题:

  private static final ThreadLocal<String> uuid =
      ThreadLocal.withInitial(() -> UUID.randomUUID().toString());

在我的例子中,每个线程多次调用 call(),所以我不得不将 UUID.randomUUID() 移动到 call()

老实说,我认为你找错人了。这里真正的问题是(显然)non-thread-safe 您使用 UUID.randomUUID 的方式。 (您没有向我们展示相关代码,因此我们无法为您找出实际问题!)最好的解决方案是找到并修复线程安全问题。

不要尝试实现自己的 random/unique 字符串生成器。这样做只会造成更多问题。

例如,您像这样使用 Random 会有效地将您限制为 ~2^48 个不同的 UUID ... 因为那是 Random 的种子长度;参见 https://docs.oracle.com/javase/8/docs/api/java/util/Random.htmlThreadLocalRandom有同样的问题

即使你的实现是正确的,你仍然需要处理底层的线程安全问题。并且您已经向代码库中添加了一堆 (IMO) 不必要的代码,这些代码需要进行彻底的单元测试……并且必须在代码库的整个生命周期内进行维护。