本ページはプロモーションが含まれています

Java入門

Java乱数の作り方|範囲指定・0〜10対応【2026年版】

CATEGORY
REV.
DRAWN BY
TOM
SHEETS
9枚
Random(範囲指定の乱数の作り方)

トム

SESで約8年、環境を変えられないもどかしさの中にいました。32歳で自社開発企業に転職し、今はClaude Codeと自動化で、仕事も時間も組み直している途中です。
・Javaバックエンドエンジニア(Java歴12年以上)
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎
詳細なプロフィール

𝕏

Javaで「1〜10」「0〜10」のような範囲指定の乱数を作るなら、rand.nextInt(max - min + 1) + min の公式1つで足ります。

1〜10なら nextInt(10) + 1、0〜10なら nextInt(11)、-10〜10なら nextInt(21) - 10です。

Java 17以降なら rand.nextInt(1, 11) のように、下限と上限を直接書く方法もあります。

乱数を作るクラスは主に4つあり、用途で使い分けます。

  • Math.random:手軽・お試し用
  • Random:汎用・シングルスレッド
  • ThreadLocalRandom:並列処理・Webサーバー
  • SecureRandom:トークンや暗号鍵などセキュリティ用途

公式の考え方に加えて、並列処理やセキュリティ用途で踏みやすい落とし穴も、Javaで実行確認したコードで紹介します。

この記事でわかること

  1. Math.random()
  2. Random クラス
  3. ThreadLocalRandom クラス
  4. SecureRandom クラス

Java乱数とは、Math.random()やjava.util.Randomなどの標準クラスを使って生成する、実行のたびに変化する数値のことです。

ゲームのアイテム抽選からテストデータの自動生成、暗号トークンの発行まで幅広い用途で使われています。

PARTS LIST /目次

Javaで乱数を使うシーンとは?

乱数は「予測できない値」が欲しい場面で使います。代表的な3つの場面を見ていきます。

ゲーム開発やシミュレーションで使われる理由

乱数が最も直感的に使われるのがゲーム開発です。

たとえば次のような処理です。

  • 敵を倒したときのアイテムドロップ率(10%の確率でレアアイテムをドロップする、など)
  • 敵キャラクターの行動パターン(50%の確率で攻撃、50%の確率で防御する)
  • 攻撃時のダメージ計算(100〜120の間でランダムなダメージを与える)
  • マップの自動生成

もし乱数がなければ、敵は毎回同じアイテムを落とし、毎回同じ行動をとる予測可能なゲームになってしまいます。

乱数が生む意外性が、ゲームの面白さを支えています。

現実の現象をまねるシミュレーションでも乱数を使います。

例えば、交通渋滞のシミュレーションでは、車がランダムなタイミングで発生することで、現実的なモデルを作れます。

あわせて読む

テストデータを自動生成する場面

プログラムが正しく動作するか確認する「テスト」の場面でも、乱数は役立ちます。

システムのテストでは、大量のダミーデータが必要になることがあります。

例えば、ECサイトの会員情報テストのために、1,000人分の架空のユーザーデータ(年齢、性別、住所など)が必要だとします。

1,000人分を手作業で入力するのは大変です。

乱数を使えば、年齢を「18歳から80歳までのランダムな整数」として自動生成できます。

// 例: 18歳から80歳までの年齢をランダムに生成
// (Randomクラスの使い方は後ほど詳しく解説します)
import java.util.Random;

Random rand = new Random();
// nextInt(bound) は 0 から bound-1 までの値を返す
// (80 - 18 + 1) = 63
// 0〜62 の乱数 + 18 = 18〜80 の乱数
int age = rand.nextInt(63) + 18;

乱数を使えば、値のばらついたテストデータを短時間で大量に用意できます。

確率的な処理を実装するケース

特定の確率に基づいて処理を分岐させたい場合にも、Javaの乱数が使われます。

代表的な例が「A/Bテスト」です。

WebサイトのデザインAとデザインBのどちらがより効果的か試したい場合、アクセスしてきたユーザーをランダムに振り分けます。

  • 50%のユーザーにはデザインAを表示
  • 50%のユーザーにはデザインBを表示

A/Bの振り分けは、0.0以上1.0未満の乱数を作り「0.5未満ならA、それ以外ならB」と判定するだけで作れます。

他にも、抽選システムや、機械学習における「モンテカルロ法」のような確率的アルゴリズムにも、乱数の考え方が応用されています。

乱数で何百通りも計算する例として、お金の増え方シミュレーターでは、値動きを乱数でゆらして積立の結果の幅を出しています(JavaScriptで書いています)。

Javaで乱数を生成する基本方法

乱数を作る基本の方法は、Math.random()・Random・ThreadLocalRandom の3つです。セキュリティ用途の SecureRandom は、後半の「より安全な乱数を使いたい場合」で扱います。

Math.random()の使い方

Math.random() は、Javaで最も手軽に乱数を使えるメソッドです。

static メソッドなので、new でインスタンスを作らずにMath.random() と書くだけで呼び出せます。

// Math.random() の呼び出し
double randomValue = Math.random();
System.out.println(randomValue); 
// 出力例: 0.845... や 0.123... など

押さえておきたい特徴は2つです。

  1. 0.0以上、1.0未満の double 型(小数)の値を返す
  • 0.0 は含まれますが、1.0 は含まれません (0.0 <= 戻り値 < 1.0)。
  1. 内部的には Random クラスが使われている
  • 中身は Random クラスの nextDouble() と同じです。

単純に0から1未満の小数が欲しい場合に適しています。

あわせて読む

Randomクラスの基本的な使い方

java.util.Random クラスは、Javaで乱数を扱う際の基本となるクラスです。

Math.random() と違い、最初に new Random() でインスタンスを作ってから使います。

import java.util.Random;

// 1. Randomクラスのインスタンスを生成
Random rand = new Random();

// 2. 乱数を取得するメソッドを呼ぶ
int intValue = rand.nextInt();        // int型の範囲でランダムな整数
int intValueBounded = rand.nextInt(10); // 0以上、10未満のランダムな整数
double doubleValue = rand.nextDouble(); // 0.0以上、1.0未満のランダムな小数
boolean boolValue = rand.nextBoolean(); // true または false

Random クラスは Math.random() よりも多機能です。

nextInt() で整数、nextDouble() で小数、nextBoolean() で真偽値など、さまざまな型の乱数を生成できます。

整数や真偽値も使うなら、Math.random() より Random クラスを選んでください。

あわせて読む

ThreadLocalRandomとの違い

java.util.concurrent.ThreadLocalRandom クラスは、マルチスレッド環境での利用に特化した乱数クラスです。

使い方は Random クラスと似ていますが、new でインスタンスを生成しません。

ThreadLocalRandom.current() という static メソッドを使って、現在のスレッド専用の乱数ジェネレータを取得します。

import java.util.concurrent.ThreadLocalRandom;

// 現在のスレッド用のジェネレータを取得
ThreadLocalRandom tlr = ThreadLocalRandom.current();

// 使い方 (Randomクラスとほぼ同じ)
int intValue = tlr.nextInt(10); // 0以上、10未満の整数
double doubleValue = tlr.nextDouble(); // 0.0以上、1.0未満の小数

Random クラスのインスタンスを複数のスレッドで共有すると、処理の競合が発生してパフォーマンスが低下します。

ThreadLocalRandom は、スレッドごとに独立した乱数ジェネレータを管理するため、競合が発生しません。

Webサーバーのような並列処理が前提の環境では、Random よりも ThreadLocalRandom を使う方が高速です。

なお、Java 17以降では RandomGenerator インターフェース経由で RandomGeneratorFactory.of("L64X128MixRandom") のような新世代アルゴリズム(JEP 356)も選択できます。

Java乱数を範囲指定して作る方法

結論: Javaで「a以上b以下の整数乱数」を作るには rand.nextInt(b - a + 1) + a の公式1つでOK。

1〜10なら rand.nextInt(10) + 1、0〜10なら rand.nextInt(11)、5〜10なら rand.nextInt(6) + 5、-10〜10なら rand.nextInt(21) - 10 です。

範囲指定の乱数は、実務でいちばん出番が多い使い方です。ここからは Math.random() と Random の2通りで、計算の中身を確認します。

nextInt(個数) + 最小値 で範囲がずれる
RANGE / 欲しい範囲
COUNT / 個数
nextInt(個数)
+ 最小値
1〜10rand.nextInt(10) + 1
10 - 1 + 1 = 10
0〜910個
1〜10
5〜10rand.nextInt(6) + 5
10 - 5 + 1 = 6
0〜56個
5〜10
NOTE公式は rand.nextInt(max - min + 1) + min。nextInt(bound) は0以上bound未満の整数を返すので、0から始まる値を最小値の分だけずらします。

Math.random() を使う場合

Math.random() は 0.0 以上 1.0 未満の小数を返します。この小数を範囲指定の整数に変えるには、ひと手間の計算が必要です。

「(最大値 - 最小値 + 1) を掛けて、最小値を足す」

  • 例1: 0〜10 (両端を含む) の整数
    • 最大値 = 10, 最小値 = 0
    • 欲しい個数 = (10 - 0 + 1) = 11個 (0, 1, ..., 10)
    • Math.random() * 11 は、0.0 以上 11.0 未満の小数
    • これを (int) でキャスト(整数化)すると、0〜10 の整数が得られます。
// 0〜10 のランダムな整数
int min = 0; int max = 10;
int randomInt = (int)(Math.random() * (max - min + 1)) + min;
System.out.println(randomInt);
  • 例2: 5〜10 (両端を含む) の整数
    • 最大値 = 10, 最小値 = 5
    • 欲しい個数 = (10 - 5 + 1) = 6個 (5, 6, 7, 8, 9, 10)
    • Math.random() * 6 は、0.0 以上 6.0 未満 (→ 整数化で 0〜5)
    • これに最小値 5 を足します。
// 5〜10 のランダムな整数
int min = 5;
int max = 10;
int randomInt = (int)(Math.random() * (max - min + 1)) + min;
System.out.println(randomInt);

Random または ThreadLocalRandom を使う場合

Random クラスには範囲指定を簡単にする nextInt(bound) が古くから用意されています。

マルチスレッド環境向けの ThreadLocalRandom はJava 7以降で利用できます。

なお、Java 17以降では nextInt(int origin, int bound) のように下限・上限を直接指定できる RandomGenerator 系APIも追加されています(JEP 356)。

  • nextInt(int bound): 0以上、bound 未満 の整数を返します。

この bound に「欲しい個数」を指定するのがコツです。

  • 例1: 0〜10 (両端を含む) の整数
    • 欲しい個数は 11個 (0〜10)
    • bound に 11 を指定します。
Random rand = new Random();
// 0以上、11未満 (つまり 0〜10) の整数
int randomInt = rand.nextInt(11);
System.out.println(randomInt);
  • 例2: 5〜10 (両端を含む) の整数
    • 欲しい個数は 6個 (5〜10)
    • bound に 6 を指定します。rand.nextInt(6) は 0〜5 を返します。
    • これに最小値 5 を足します。
Random rand = new Random();
int min = 5; int max = 10;
// (max - min + 1) = 6
// 0〜5 の乱数 + 5 = 5〜10 の乱数
int randomInt = rand.nextInt(max - min + 1) + min; System.out.println(randomInt);

キャストが不要なぶん、Random クラスの方が計算ミスを起こしにくくおすすめです。

Java 17以降は、Random でも nextInt(下限, 上限) が使えます。上限は含まないので、1〜10なら nextInt(1, 11) と書きます。

// Java 17以降: 下限(含む)と上限(含まない)を直接指定
Random rand = new Random();
int dice = rand.nextInt(1, 7);    // 1〜6(サイコロ)
int oneToTen = rand.nextInt(1, 11); // 1〜10

// ThreadLocalRandom は Java 7 から同じ書き方ができる
int n = ThreadLocalRandom.current().nextInt(1, 11); // 1〜10

Java乱数をint・doubleで扱う方法

結論として、int型は nextInt()、double型は nextDouble() を使えば整数・小数どちらの乱数も簡単に生成できます。

クラス速度(相対)スレッドセーフ予測可能性主用途
Math.random速い○(内部のRandom1つを全スレッドで共有)予測可能サンプル・お試し
Random速い○(シードをCASで更新)予測可能シングルスレッド汎用
ThreadLocalRandom最速(スレッド間の取り合いなし)○(スレッド固有)予測可能マルチスレッド・Webサーバー
SecureRandom遅い(十倍〜数十倍)○予測困難(CSPRNG)トークン・暗号鍵

※速度は一般的な傾向です。実際の差はJavaのバージョンや実行環境、スレッド数で変わります。

SecureRandom は初回 nextBytes() で内部の初期化(OSの乱数源からの読み込みなど。中身はOSと実装で異なります)が走るため、特に最初の数回で顕著に重くなります。

小数の乱数を生成する

nextDouble() メソッドを使います。

このメソッドは、Math.random() と同様に、0.0以上、1.0未満 の double 型の値を返します。

Random rand = new Random();
double d1 = rand.nextDouble(); // 0.0 <= d1 < 1.0
System.out.println(d1);

もし「0.0以上、50.0未満」のように範囲を指定したい場合は、結果を乗算します。

Random rand = new Random();
// 0.0〜1.0 の乱数に 50.0 を掛ける
double d50 = rand.nextDouble() * 50.0; // 0.0 <= d50 < 50.0
System.out.println(d50);

整数の乱数を生成する

nextInt() メソッドを使います。

nextInt() には、引数なしと引数ありの2種類があります。

  • nextInt() (引数なし):int 型が取りうる全範囲(約-21億から+21億)のランダムな整数を返します。
Random rand = new Random();
int i = rand.nextInt();
// -2,147,483,648 〜 2,147,483,647
System.out.println(i);
  • nextInt(int bound) (引数あり):0以上、bound 未満 のランダムな整数を返します。bound には正の数を指定してください。実務で使うのはほぼこちらです。
Random rand = new Random();
// 0以上、100未満 (0〜99)
int i100 = rand.nextInt(100);
System.out.println(i100);

負の数を含む範囲で乱数を作る

「-10から+10まで」のように、負の数を含む範囲の乱数を作るには、nextInt(bound) と最小値の加算を組み合わせます。

公式は先ほどと同じです。

rand.nextInt(最大値 - 最小値 + 1) + 最小値

  • 例: -10〜+10 (両端を含む) の整数
    • 最大値 = 10
    • 最小値 = -10
    • 欲しい個数 (bound) = 10 - (-10) + 1 = 10 + 10 + 1 = 21
    • nextInt(21) は 0〜20 の整数を返します。これに最小値 -10 を足します。
    この計算式を覚えておけば、Javaであらゆる範囲の整数乱数を生成できます。
Random rand = new Random();
int min = -10;
int max = 10;
int bound = max - min + 1; // 21
int randomInt = rand.nextInt(bound) + min;
System.out.println(randomInt); // -10 から 10 までの値が出力される

より安全な乱数を使いたい場合

これまで紹介した Random や ThreadLocalRandom は、ゲームやシミュレーションには十分です。

しかし、セキュリティが要求される用途には使えません。

SecureRandomの使い方

暗号化キー、セッショントークン、パスワード生成など、セキュリティ上「予測不可能」であることが重要な場合には、java.security.SecureRandom クラスを使います。

使い方は Random クラスと似ています。

import java.security.SecureRandom;

// 1. SecureRandomのインスタンスを生成
SecureRandom secRand = new SecureRandom();

// 2. 乱数を取得する (Randomクラスと同じメソッドが使える)
int intValue = secRand.nextInt(100); // 0〜99
double doubleValue = secRand.nextDouble(); // 0.0〜1.0

// セキュリティ用途では byte配列 を使うことが多い
byte[] randomBytes = new byte[16];
secRand.nextBytes(randomBytes); // 16バイトのランダムな値で配列を満たす

SecureRandom は、OSが提供するランダムネス(マウスの動き、ネットワークのタイミングなど)を利用するため、Random よりも生成コストが重くなります。

そのぶん、出力を予測されにくい乱数になります。

Java 8以降は SecureRandom.getInstanceStrong() を使うと、OSが推奨する強力なアルゴリズム(Linuxなら NativePRNGBlocking など)を自動で選択できます。

暗号用途でRandomを使ってはいけない理由

Random クラス(Math.random や ThreadLocalRandom も含む)を暗号用途に使ってはいけません。

これらは「疑似乱数ジェネレータ(PRNG)」で、計算式から次の値を予測できるためです。

Random クラスは、「シード (Seed) 値」と呼ばれる初期値をもとに、特定の計算式で次の乱数を生成します。

もし攻撃者がこの「シード値」やアルゴリズムを知ってしまうと、過去と未来の乱数系列をすべて再現できてしまいます。

例えば、パスワードリセットトークンを Random で生成したとします。

攻撃者がそのパターンを解析し、次に生成されるトークンを予測できれば、他人のアカウントを乗っ取れてしまいます。

一方、SecureRandom は 「暗号論的に強力な疑似乱数ジェネレータ (CSPRNG)」 です。

内部のシード値が予測不可能であり、たとえいくつかの出力値が知られても、次の値を予測することは事実上不可能です。

セキュリティが関わる場所では、必ず SecureRandom を使う。これは Java開発における鉄則です。

乱数の再現性とシード値とは?

Random クラスが「予測可能」である性質は、セキュリティ面では弱点です。しかし、テストやデバッグの際には、逆に大きなメリットとなります。

シード値を指定して同じ乱数を生成する方法

Random クラスは、インスタンス化の際に「シード値」と呼ばれる long 型の数値を渡せます。

Random rand = new Random(シード値);

シード値を指定すると、その Random インスタンスは、必ず同じ順番で同じ乱数系列を生成します。

// 1. シード値 12345L でインスタンスを生成
Random rand1 = new Random(12345L);
System.out.println("--- rand1 ---");
System.out.println(rand1.nextInt(100)); // 1回目
System.out.println(rand1.nextInt(100)); // 2回目
System.out.println(rand1.nextInt(100)); // 3回目

// 2. もう一度、同じシード値 12345L でインスタンスを生成
Random rand2 = new Random(12345L);
System.out.println("--- rand2 ---");
System.out.println(rand2.nextInt(100)); // 1回目
System.out.println(rand2.nextInt(100)); // 2回目
System.out.println(rand2.nextInt(100)); // 3回目

Java 23で実行すると、rand1 と rand2 はどちらも 51, 80, 41 の順に出力され、完全に一致します。

シード値を指定しない new Random() は、ナノ秒単位の時刻(System.nanoTime())と内部カウンタを組み合わせた値をシードに使います。

そのため、実行するたびに異なる乱数系列になります。

テストやデバッグでシード値を使うメリット

乱数を再現できる性質は、バグの原因を突き止めるときに役立ちます。

例えば、乱数を使うゲームで「特定の状況でだけバグが発生する」とします。もしシード値を指定していなければ、そのバグを再現するのは困難です。

しかし、テスト実行時にシード値を固定(または記録)しておけば話は変わります。

バグが発生した際のシード値を使えば、何度でも 「バグが発生した状況」を100%再現 できます。

再現できないバグは、修正できたかどうかも確かめられません。シード値をログに残しておけば、乱数が絡むバグも同じ条件で再現できます。

乱数を使うときの注意点

ここからは、乱数で踏みがちなアンチパターンを3つ紹介します。

公式ドキュメントを読むだけでは気付きにくい、本番運用で踏みがちな落とし穴です。

毎回new Random()を呼ばないほうがいい理由

初心者にありがちな間違いが、乱数が必要になるたびに new Random() を呼び出すことです。

// 悪い例: ループの中で毎回 new Random() する
public void printRandoms() {
    for (int i = 0; i < 100; i++) {
        // 非常に短い時間で new が繰り返される
        Random rand = new Random(); 
        System.out.println(rand.nextInt());
    }
}

このコードの問題は2つあります。

  1. ループのたびに Random オブジェクトを作り、すぐ捨てる無駄が生じる
  2. インスタンスが毎回変わるので、シード値を固定して結果を再現するテストが書けない

古い解説では「同じ時刻のシードになり、同じ値が続く」と説明されることがあります。これはJava 1.4以前の話です。当時の new Random() はミリ秒単位の時刻をそのままシードにしていました。

Java 5以降は、ナノ秒の時刻と内部カウンタを組み合わせてシードを作ります。Java 23で new Random() を100回連続で生成したところ、最初の値は100通りすべて異なりました。

値が重なる心配はなくても、上の2つの理由から毎回の生成は避けてください。

Random インスタンスは、一度だけ生成し、それを使い回すのが正しい使い方です。

// 良い例: インスタンスを使い回す
// (フィールドとして保持する)
private Random rand = new Random(); 

public void printRandoms() {
    for (int i = 0; i < 100; i++) {
        // 同じインスタンスを使い回す
        System.out.println(rand.nextInt());
    }
}

並列処理での乱数の扱い方

「Random インスタンスは使い回す」のが基本です。

しかし、Webサーバーのように複数のスレッドが同時にそのインスタンスにアクセスする環境では、別の問題が発生します。

Random クラスはスレッドセーフです。ただし、内部のシード値は1つの変数(AtomicLong)で、全スレッドがこれを取り合って更新します。

更新はCAS(値を比べて、変わっていなければ書き換える方式)で行われます。多数のスレッドが同時に呼ぶと更新の衝突とやり直しが増え、待ち時間がボトルネックになります。

アクセスが集中するWebサーバーでは、この待ち時間が応答速度の低下につながります。

この問題を解決するのが ThreadLocalRandom です。

ThreadLocalRandom.current() は、スレッドごとに独立した乱数ジェネレータを提供します。

スレッド同士の取り合いが起きないため、マルチスレッド環境でも高速に動作します。

並列処理が想定される場面では、Random ではなく ThreadLocalRandom を選びましょう。

一見ランダムに見えて偏るケース

乱数の範囲指定で、nextInt(bound) を使わずに %(剰余) を使うと、乱数に「偏り」が発生する場合があります。

// 偏りが発生する可能性のある悪い例
Random rand = new Random();
// 0〜9 の乱数が欲しいとする
int randomInt = Math.abs(rand.nextInt()) % 10;

rand.nextInt() は、int の全範囲(約42億通り)の値を返します。

この全範囲の個数が、もし10で割り切れない場合、% 10 の結果(0〜9)は均等に出現しません。

例えば、Integer.MAX_VALUE (2,147,483,647) は10で割り切れません。

そのため、0〜7 の数字は、8や9 よりもわずかに多く出現してしまいます。

このコードには、偏りより深刻な落とし穴もあります。Math.abs(Integer.MIN_VALUE) は正の数にならず、-2147483648 のまま返ります。

Java 23で確かめると、この値の % 10 は -8 でした。約42億回に1回、0〜9の範囲外の値が混ざります。

この剰余演算による偏りは微妙で、ほとんどの用途では問題になりません。

しかし、統計やシミュレーションの正確性が求められる分野では、この偏りが結果に影響を与えることがあります。

rand.nextInt(10) は、偏りの原因になる端数の値を捨てて引き直す処理が内部に入っており、0〜9 が均等に出ます。

範囲指定の整数が欲しい場合は、% ではなく nextInt(bound) を使うのが安全で確実です。

Java乱数のよくある質問(FAQ)

Q. Math.randomとRandomクラスはどちらを使えばいい?

A. 整数や真偽値など複数の型が必要ならRandomクラス、0.0〜1.0の小数1つだけでよいならMath.random()が手軽です。内部実装は同じRandomなので乱数の品質に差はありません。

Q. java で 1 から 10 の乱数を作るには?

A. new Random().nextInt(10) + 1 で1〜10の整数(両端を含む)を生成できます。一般化すると nextInt(max - min + 1) + min です。

Q. nextInt() に負の数や0を渡すとどうなる?

A. IllegalArgumentException: bound must be positive が発生します。nextInt(bound) のboundは必ず正の整数を指定してください。

Q. SecureRandomは遅いと聞いたが、いつ使うべき?

A. パスワードリセットトークン・セッションID・暗号鍵など「予測されると損害が発生する」用途では必ずSecureRandomを使います。ゲームのドロップ判定やテストデータならRandomかThreadLocalRandomで十分です。

Q. Javaで乱数の重複を防ぐには?

A. HashSetやLinkedHashSetに生成した乱数を追加し、サイズが増えなければ再生成するループで重複を除去できます。少数の重複回避ならこの方法で十分です。

Q. Javaでtrue/falseのランダムな真偽値を作るには?

A. RandomクラスのnextBoolean()を使います。50%の確率でtrue、50%の確率でfalseを返し、引数は不要です。

Q. new Random(シード値) を使うと必ず同じ結果になりますか?

A. はい。同じシード値を指定したRandomインスタンスは、呼び出し順序が同じであれば必ず同じ乱数系列を返します。テストの再現性確保に活用できます。

Q. ThreadLocalRandomはシングルスレッドでも使えますか?

A. はい、使えます。ただしスレッド間の取り合いがないことによる恩恵はマルチスレッド環境でこそ発揮されます。シングルスレッドでもThreadLocalRandomのほうが速い傾向はありますが、1回あたりの差はナノ秒単位なので、Randomでも実用上はほとんど気になりません。

あわせて読む

まとめ:用途に応じて乱数クラスを使い分けよう

Javaには複数の乱数生成方法がありますが、それぞれに明確な役割があります。

多くの解説記事はMath.randomとRandomの2択で終わりがちです。しかし実務では、それだけでは足りません。

並列処理が前提のWebサーバーならThreadLocalRandom、トークンや暗号鍵が絡むならほぼ確実にSecureRandomが要求されます。

つまり実際の現場で問われるのは「Math.randomかRandomか」ではなく、この4クラスから用途に応じて正しく選べるかどうかです。

迷ったときは、次の順に質問に答えていけば使うクラスが決まります。

乱数クラスの選び方(Q1から順に答える)
QUESTION / 質問
はい
いいえ
Q1. トークン・パスワード・暗号鍵など、予測されると困る用途?
SecureRandom
Q2へ
Q2. 複数のスレッドから同時に使う?
ThreadLocalRandom.current()
Q3へ
Q3. シード値を固定して結果を再現したい?
new Random(シード値)
Q4へ
Q4. 0.0〜1.0未満の小数が1つ欲しいだけ?
Math.random()
Q5へ
Q5. Java 17以降でアルゴリズムも選びたい?
RandomGeneratorL64X128MixRandom など
new Random()

汎用 → Random

  • new Random()
  • シングルスレッド環境(通常のバッチ処理やシンプルなアプリ)で、セキュリティを問わない一般的な乱数を扱う場合の基本です。
  • シード値を指定できるため、テストでの再現性担保にも役立ちます。

並列処理 → ThreadLocalRandom

  • ThreadLocalRandom.current()
  • Webサーバーや並列処理など、マルチスレッド環境で使うべき選択肢です。
  • スレッド間の競合が発生せず、パフォーマンスが最も優れています。

セキュリティ → SecureRandom

  • new SecureRandom()
  • パスワード、トークン、暗号キーなど、予測不可能性が求められるセキュリティ関連の処理で 必須 です。
  • 他のクラスよりも生成コストは高いですが、最も安全です。

Javaの乱数を正しく使い分けることは、バグが少なく、パフォーマンスが高く、安全なアプリケーションを作るための第一歩です。

REVISIONS / 改訂履歴
REV.DATE内容
62026-10-15図解を描き直し(図面のデザインにそろえた)
52026-10-14雰囲気だけの挿絵を外した
42026-10-04記載内容の事実確認と修正
32026-08-202026年8月時点の情報で全体を見直し
… ほか1回の改訂
12025-11-08初版
NEXT READ本棚から1本

AIで開発を組み直すなら、まずこの5冊から

入門・実践・設計まで、Claude Codeの本をレベル別に5冊選んで比べました。

→ おすすめ5冊を見る

  • この記事を書いた人
  • 最新記事

トム

SESで約8年、環境を変えられないもどかしさの中にいました。32歳で自社開発企業に転職し、今はClaude Codeと自動化で、仕事も時間も組み直している途中です。
・Javaバックエンドエンジニア(Java歴12年以上)
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎
詳細なプロフィール

𝕏

Java入門