Javaにおける乱数生成の方法と各クラスの特性

Javaでは、RandomThreadLocalRandomSecureRandom の3つの主要なクラスを使って乱数を生成できます。それぞれ異なる用途や性能特性を持ち、適切に使い分けることが重要です。

擬似乱数生成器 Random

java.util.Random は最も基本的な乱数生成クラスで、指定したシード値に基づいて決定論的な数列を生成します。同じシードと呼び出し順序であれば、常に同じ結果が得られます。これは「擬似乱数」と呼ばれ、真のランダム性はありません。

Random gen = new Random(System.currentTimeMillis());
int val = gen.nextInt(100); // 0〜99の整数

デフォルトでは現在時刻をシードとして使用しますが、明示的に固定値を渡すと再現可能なシーケンスが得られます。これはテストやデバッグには便利ですが、セキュリティ用途には不向きです。

並行処理向け ThreadLocalRandom

java.util.concurrent.ThreadLocalRandom は、マルチスレッド環境での性能向上のために設計されたクラスです。内部でThreadLocalを利用し、各スレッドが独立した乱数生成器を持つため、ロック競合が発生しません。

ThreadLocalRandom localRand = ThreadLocalRandom.current();
int boundedInt = localRand.nextInt(5, 20);   // 5以上20未満
double boundedDouble = localRand.nextDouble(1.5, 8.5); // 1.5以上8.5未満

このクラスはシードの設定をサポートしておらず、setSeed() を呼ぶと例外がスローされます。これは意図的に再現性を排除し、スレッドごとの独立性を保つためです。

セキュアな乱数 SecureRandom

java.security.SecureRandom は、暗号学的に安全な乱数を生成するためのクラスです。予測困難なエントロピー源(ハードウェアノイズ、システムイベントなど)を活用し、外部からの推測を極力防ぎます。

SecureRandom secureGen = new SecureRandom();
byte[] token = new byte[16];
secureGen.nextBytes(token); // 暗号トークン生成に適している

高負荷時には生成速度が遅くなる場合がありますが、パスワードリセットトークンやセッションID、認証コードなどのセキュリティ関連用途には必須です。

選択の指針

  • 一般用途・単一スレッドRandom
  • 高スループット・マルチスレッドThreadLocalRandom
  • セキュリティ要件ありSecureRandom

また、Java 8以降ではints()longs()doubles()メソッドにより、ストリーム形式で乱数を生成することも可能です。例えば、10個の0〜50の整数を生成するには以下のように書けます:

IntStream randomStream = ThreadLocalRandom.current().ints(10, 0, 50);
randomStream.forEach(System.out::println);

タグ: Java random threadlocalrandom securerandom 乱数生成

6月22日 20:32 投稿