在多线程应用程序中生成相同的 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
:
我看到了同样的事情。我在 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.html。 ThreadLocalRandom
有同样的问题
即使你的实现是正确的,你仍然需要处理底层的线程安全问题。并且您已经向代码库中添加了一堆 (IMO) 不必要的代码,这些代码需要进行彻底的单元测试……并且必须在代码库的整个生命周期内进行维护。
我正在使用 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
:
我看到了同样的事情。我在 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.html。 ThreadLocalRandom
有同样的问题
即使你的实现是正确的,你仍然需要处理底层的线程安全问题。并且您已经向代码库中添加了一堆 (IMO) 不必要的代码,这些代码需要进行彻底的单元测试……并且必须在代码库的整个生命周期内进行维护。