Is the random generator in Scala thread-safe

Viewed 154

I have the following code:

import scala.util.Random

val seq = Seq[Int](1, 2, 3)
val rand = new Random(123)
val gen = seq.par.map(_ => rand.nextInt(3))
println(gen.seq)

It prints out Vector(2, 2, 2).
It seems that the random generator in Scala is not thread-safe?
Is that true? If so, how I could tackle with it on top of using different seeds for different threads.
Also, if I use the random class in Java in Scala, will that still be thread-safe?
Related Question


Explanation
par refers to the par in scala.collection.parallel.immutable. But it seems that my computer doesn't require me to do that. And it runs on my computer.

1 Answers

Yes. Same as in Java. Let's take a look at the implementation of next, which is the random generator behind nextInt:

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));
}

Basically we compute based on seed the next element. In case the seed was already changed, it will create a new nextseed, until it succeeded to update the seed. Therefore it is thread safe.

From the same reason, it seems then in your scenario, it isn't. But, if we run the same without any parallelism, we'll get get same result.

import scala.util.{Failure, Random, Success}

val seq = Seq[Int](1, 2, 3)
val rand = new Random(123)
val gen = seq.map(_ => rand.nextInt(3))
println(gen.seq)

will result with:

List(2, 2, 2)

Code run at Scastie. This is becuase the first three "random" numbers for seed 123, are 2, 2, 2

Related