なぜRandomではなくThreadLocalRandomを使用するのですか?


n/a.結論java.util.Randomは、マルチスレッド環境において、1つのインスタンスから擬似乱数(pseudorandom)をグローバルに返す.したがって、同じ時間にリクエストが同時に受信されると、競合状態でパフォーマンスに問題が発生する可能性があります.逆に、JDK 7から導入されたjava.util.concurrent.ThreadLocalRandomjava.util.Randomを継承し、マルチスレッド環境では異なるインスタンスから擬似乱数が返されるため、同期性の問題に対して安全である.(ランダム特性上、同じ数が発生しても設計上の問題ではなく、正常に動作します)
Javaが整数を生成する原理
基本的に、コンピュータは数学的に完全な整数を生成できません.コンピュータは同じ入力と同じ出力を保証しなければならない決定的な有限自動機であるからだ.完全な暖水を生成するために、精密工学界も複雑なシステムの熱特性を利用して物理暖水を製造しているが、これはソフトウェア開発者が直面すべき状況ではない.
したがって,Javaのような言語はシード(Seed)と対応する乱数の対応によって乱数を決定する.ハッシュ関数の原理や高校数学に似た一般的なログテーブル.これは、同じシードが与えられた場合、生成されるシード数は同じであり、ランダム数を設計的に作成するためには、異なるシードを提供する必要があることを意味する(学習、テストの目的のためにシードを固定し、返されるシード数の順序を同じにする場合がある).
JavaはSeedを指定せず,コンピュータの現在の時間を利用して乱順に対応する.
public Random() {
        this(seedUniquifier() ^ System.nanoTime());
    }
public Random(long seed) {
        if (getClass() == Random.class)
            this.seed = new AtomicLong(initialScramble(seed));
        else {
            // subclass might have overriden setSeed
            this.seed = new AtomicLong();
            setSeed(seed);
        }
    }
private static long seedUniquifier() {
        // L'Ecuyer, "Tables of Linear Congruential Generators of
        // Different Sizes and Good Lattice Structure", 1999
        for (;;) {
            long current = seedUniquifier.get();
            long next = current * 1181783497276652981L;
            if (seedUniquifier.compareAndSet(current, next))
                return next;
        }
    }
Randomはなぜマルチスレッドで危険な状態にあるのかjava.util.Randomは、マルチスレッド内でランダムなインスタンスを共有し、グローバルに動作する.
同じnanoTimeでマルチスレッドからのリクエストを受信したらどうなりますか?同じ値を返しますか?
そうしなくてよかった.Randomの擬似乱数生成は線形連合生成器(Linear Congriential Generator)アルゴリズムを採用し、1つのスレッドは同時に競争する中で勝って、もう1つのスレッドは自分が勝つまで同じ操作を繰り返します.
private final AtomicLong seed;

protected int next(int bits) {
    long oldseed, nextseed;
    AtomicLong seed = this.seed;
    do {
        oldseed = seed.get();
        nextseed = (oldseed * multiplier + addend) & mask;
    } while (!seed.compareAndSet(oldseed, nextseed));

    return (int)(nextseed >>> (48 - bits));
}
複数のスレッドが競合-失敗-再挑戦を同時に行う場合、パフォーマンス上の深刻な問題が発生する可能性があります.割引クーポンをランダムに返却するイベントで同時に数万人のリクエストを受けたら?散々殴られたサーバーで怒ったユーザーの罵倒から開発者の精神を救うには、他の方法が必要だ.
なぜThreadLocalRandomを使うのですか?java.util.concurrent.ThreadLocalRandomは同様にRandom APIの実装体であり、java.util.Randomを継承する.ThreadLocalRandomは、上述した同期性の問題を解決するために、各スレッドによって生成されたインスタンスにおいてそれぞれ1つの整数を返す.したがって、Randomのような競合問題は発生しないため、セキュリティ上、パフォーマンス上のメリットがあります.Randomの代わりにThreadLocalRandomを使用します.
public static ThreadLocalRandom current() {
        if (U.getInt(Thread.currentThread(), PROBE) == 0)
            localInit();
        return instance;
    }
使用例
0から9の整数を返すクラスがRandomに設定されている場合、
public class MyRandom {
	private static final int RANDOM_BOUND = 10;

	private static final Random random = new Random();
	
	public int getNumber() {
		return random.nextInt(RANDOM_BOUND);
	}
}
同じ役割を持つクラスがThreadLocalRandomに設定されている場合は、次のように作成できます.
public class MyRandom {
	private static final int RANDOM_BOUND = 10;

	private static final ThreadLocalRandom random = ThreadLocalRandom.current();

	public int getNumber() {
		return random.nextInt(RANDOM_BOUND);
	}
}
リファレンス
https://www.baeldung.com/java-thread-local-random#:~:text=The%20random%20number%20obtained%20by,support%20setting%20the%20seed%20explicitly .
https://www.concretepage.com/java/jdk7/threadlocalrandom-java-example
https://namocom.tistory.com/733
https://www.4te.co.kr/945#:~:text=%EC%BD%94%EB%93%9C%20%EB%82%B4%EC%97%90%EC%84%9C%20%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94,%EC%9D%84%20%EA%B8%B0%EC%B4%88%EB%A1%9C%20%EB%A7%8C%EB%93%A4%EA%B2%8C%20%EB%90%9C%EB%8B%A4 .
https://needneo.tistory.com/70
https://ko.wikipedia.org/wiki/%EC%84%A0%ED%98%95_%ED%95%A9%EB%8F%99_%EC%83%9D%EC%84%B1%EA%B8%B0