在我的 Spring 應用程式中,如果我有一個ThreadLocalRandom在構造程序中設定的類成員:
public class RNG {
private ThreadLocalRandom rng;
public RNG() {
rng = ThreadLocalRandom.current();
}
public int getInt() {
return rng.nextInt(1000, 10000);
}
}
// some other class
RNG a = new RNG();
a.getInt();
回傳的第一個 int 始終相同,即使在應用程式重新啟動時也是如此。如果我改為修改getInt()方法:
public int getInt() {
return ThreadLocalRandom.current().nextInt(1000, 10000);
}
我每次都會得到偽隨機值,即使在應用程式重新啟動時(這是我所期望的)。這似乎只發生在春天。我在jshell和Replit中嘗試過相同的方法,但沒有看到這種行為。對于背景關系,生成亂數的 Spring bean 是自動裝配的。
老實說,我已經從那部分代碼中完全洗掉了亂數生成,而是使用注入的依賴項,所以我可以對其進行單元測驗。
這個問題是為了讓我更好地了解正在發生的事情。據我所知,在構建程序中設定類成員應該在應用程式重新啟動時提供不同的值。
uj5u.com熱心網友回復:
將建構式中的結果存盤在ThreadLocalRandom.current()類的實體變數中是一個壞主意。實際上ThreadLocalRandom完全可以達到目的,然后您最好使用常規的Randomor SecureRandom。
話雖如此。這與 Spring 無關,而是您將ThreadLocalRandom.current()結果存盤在實體變數中。以下程式將產生相同的結果,并且不使用 Spring。
public static void main(String[] args) throws Exception {
var rnd = ThreadLocalRandom.current();
System.out.println("Starting with RND " rnd.getClass().getName() " - " rnd.hashCode());
var executor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 50; i ) {
executor.submit(() -> System.out.println("Value: " rnd.nextInt(1000, 10000)));
}
System.out.println("Waiting to finish!");
executor.shutdown();
while (!executor.awaitTermination(50, TimeUnit.MILLISECONDS)) {
}
}
發生的事情是Random在執行緒上初始化,main隨機使用的種子等存盤在main執行緒的記憶體中。現在你啟動一個新執行緒,它試圖找到該執行緒的種子,但沒有,所以它總是以 0 為種子,因為沒有種子系結到該執行緒。
這都是由于將ThreadLocalRandomfrom main 存盤在實體變數中。(ThreadLocalRandom顧名思義)使用執行緒系結種子等來生成亂數。這就是為什么您應該始終使用ThreadLocalRandom.current()而不是將結果存盤在變數中的原因。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/437305.html
