Random.Shared in .NET9

Programming .NET C#

The Random class is not thread-safe, meaning concurrent access can lead to duplicate values or other unexpected behavior.

Seeding

In order to understand this, we have to examine how seeding the Random class works. Let's look at this code:

Random random1 = new Random(42);
Random random2 = new Random(42);

int a = random1.Next(100);
int b = random2.Next(100);        // a = b

Console.WriteLine(a); 
Console.WriteLine(b);            // same output

The code above will lead to the same "random" numbers since both were seeded equaly.

Caution: Instantiating Random multiple times in a short time frame can lead to duplicate values because the instances may be seeded with the same timestamp.  For example it it not guaranteed that this code

Parallel.For(0, 10, i =>
{
  Random rnd = new Random();
  Console.WriteLine(rnd.Next(100));
});

always returns another value while this code below, using ThreadLocal, will:

class Program
{
    private static ThreadLocal<Random> rnd = new ThreadLocal<Random>(() => new Random());

    static void Main()
    {
        Parallel.For(0, 10, i =>
        {
            Console.WriteLine(rnd.Value.Next(100));
        });
    }
}

Alright, that's "the old way".  With .NET9 Microsoft introduced Random.Shared (which is thread-safe) that significantly simplifies this:

Parallel.For(0, 10, i =>
{
    Console.WriteLine(Random.Shared.Next(100));
});