多线程应用程序生成相同UUID

9
我正在使用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;

但这种方法不够优雅,我不喜欢它。

有谁知道一种真正可靠的方法来生成随机字符串吗?

6个回答

6

您可以同步UUID生成方法,或者可以预先生成UUID池,并在池开始耗尽时在一个线程中生成更多的标识符。


2
我认为你可能在错误的方向上努力。真正的问题在于你使用了(似乎)非线程安全的 UUID.randomUUID 方法。(你没有展示相关代码,所以我们无法为你找到实际的问题!)最好的解决方法是找到并修复线程安全问题。
不要尝试自己实现随机/唯一字符串生成器。这样做只会在后面制造更多问题。
例如,你像这样使用 Random 将有效地限制你只能使用 ~2^48 个不同的 UUID……因为那是 Random 的种子长度;参见https://docs.oracle.com/javase/8/docs/api/java/util/Random.html。ThreadLocalRandom 存在相同的问题。
即使你的实现是正确的,你仍然需要处理底层的线程安全问题。而且你已经为你的代码库添加了一堆(在我看来)不必要的代码,需要进行彻底的单元测试……并且,在你的代码库的生命周期内必须维护它们。

1
你可以尝试类似这样的内容。
int uuid = ThreadLocalRandom.current().nextInt());

0

我也遇到了同样的问题。在一个多线程应用程序中,我调用了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()中。

0

0

在我的情况下,我已经尝试了所有可能的解决方案。即使是v1ma-8提供的库仍然会给我带来重复的结果。我已经发现问题与活动线程数有关...如果由同一线程获取相同的ID,这是合理的...

我使用了server.tomcat.threads.min-spare选项来增加Tomcat中的线程数进行测试,只要不超过此最小值,它就可以正常工作。


1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接