🧰 Core APIs Toolbox · Intermediate

Random numbers in Java

Random, ThreadLocalRandom, SecureRandom, RandomGenerator.

🧩 The mysteryYou roll a virtual die 1000 times and get the same face 1000 times. The code calls nextInt… so where did the randomness go?

Pseudo-random

java.util.Random isn't magic: it's an algorithm. A starting number, the seed, fully decides the sequence. Same seed → same sequence — wonderful for reproducible tests and simulations, terrible for secrets.

🔮 Predict it

Twins

What does this print?

Random a = new Random(7);
Random b = new Random(7);
System.out.println(
    a.nextInt(1000) == b.nextInt(1000));
System.out.println(
    a.nextInt(1000) == b.nextInt(1000));
  1. false false
  2. true true
  3. It varies from run to run
Show the answer

true both times — the same seed produces exactly the same sequence, on every run and every machine.

Ranges: origin in, bound out

nextInt(6) gives 0 to 5. **nextInt(origin, bound)** (on Random since Java 17) includes the origin and excludes the bound — so a six-sided die is nextInt(1, 7).

int roll = ThreadLocalRandom.current()
    .nextInt(1, 7); // 1..6

The family

**Random: general-purpose and seedable. ThreadLocalRandom.current(): fast across many threads, no contention. SecureRandom: unpredictable, for tokens, passwords and keys. Since Java 17 they all implement RandomGenerator**.

⚠️ The trap

A fresh Random every time

Creating new Random(42) inside the loop restarts the same sequence on every iteration, so every roll is identical. Create one Random outside the loop.

int[] counts = new int[6];
for (int i = 0; i < 1000; i++) {
    Random r = new Random(42); // bug!
    counts[r.nextInt(6)]++;
}
🤔 Think first

Good enough for tokens?

Why not use new Random() to generate password-reset tokens?

Think about it, then reveal the answer

Its output is predictable: after seeing a few values, an attacker can work out the internal state and predict future tokens. Use **SecureRandom**, a cryptographically strong generator.

💼 In the real world

Randomness in production

Games and simulations use seeded Random so bugs can be replayed. Load balancers and retry jitter use ThreadLocalRandom. Session IDs, reset links and API keys must use SecureRandom — predictable tokens have led to real account takeovers.

Key takeaways

  1. Same seed → same sequence (handy for tests)
  2. nextInt(a, b): a inclusive, b exclusive (Java 17+)
  3. ThreadLocalRandom.current() for concurrent code
  4. SecureRandom for tokens, passwords and keys
🤯 Did you know?

Random's algorithm (a linear congruential generator) is spelled out in its Javadoc, so a seed gives the same numbers on every JVM ever made.

Practice questions

Simulate a six-sided die (1 to 6).

int roll = ThreadLocalRandom.current()
    .nextInt(1, ___);
  1. 6
  2. 7
  3. 5
Check your answer

7. nextInt(origin, bound) includes the origin but excludes the bound, so you need 7 to make 6 possible.

You need to generate password-reset tokens. Which source of randomness should you use?

  1. new Random(System.currentTimeMillis())
  2. Math.random()
  3. SecureRandom
  4. ThreadLocalRandom.current()
Check your answer

SecureRandom. Tokens must be unguessable. SecureRandom uses a cryptographically strong generator; the others are predictable.

Next: System and Runtime — two clocks, environment variables, and a finally block that never runs.