---
title: "LinkedIn: \"Are you still using new Random() everywhere?\""
description: "You need some advice around `Random`? Sure there is something on LinkedIn for that. Let's have a look."
updated: 2025-10-27
tags: ["C#", ".NET", "LinkedIn"]
canonical: "https://steven-giesel.com/blogPost/cc2a3f52-9d35-43d2-9687-c276a2de8e07/linkedin-are-you-still-using-new-random-everywhere"
---

# LinkedIn: "Are you still using new Random() everywhere?"

You need some advice around `Random`? Sure there is something on LinkedIn for that. Let's have a look.

## `new Random` is evil!!!!11111

In this LinkedIn post, the Author does claim the following (paraphrased)
 * `new Random` uses system clock
 * if multiple instances are created in a tight loop, they generate identical results.

The claim is then supported by the following code:

**Random -> Thread Unsafe**:
```csharp
for(var i = 0; i < 5;i++)
{
    var random = new Random();
    Console.WriteLine(random.Next(1,100));
}
// Output 42, 42, 42, 42, 42
```

**Random.Shared -> Thread Safe**:
```csharp
for(var i = 0; i < 5;i++)
{
    Console.WriteLine(Random.Shared.Next(1,100));
}
// Output: 17, 82, 19, 23, 5
```

First things first, a `for` loop has nothing to do with threads. But maybe that is just a small mistake. Because if you run the "Thead Unsafe" version: The output is absolutely not the same. If you want to try it out yourself: [Be my guest](https://sharplab.io/#v2:C4LgTgrgdgPgAgJgIwFgBQAzA9mAFANwEMwACASxIF4SAGAbnIB4BWOsganYEp0BvdEoJJFSYQlAAmWALZUSUAKYB3EgCVxU6bi50BQuEgCcuMZJkA6AHIKAHsFxIANEho0uO9AF8gA=). So where is this coming from?

## .NET Framework times
In .NET Framework, `new Random` was relying on. `DateTime.Now.Ticks` which was resolved roughly every 16ms. So in a timeframe of 16 milliseconds you get the same seed, leading to the same `Next(...)` result everytime. But that isn't true anymore since the `netcore` times and especially since modern versions of the framework. Meet:

## Xoshiro256**

Let's have a look into the [`Random`](https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/Random.cs,bb77e610694e64ca) class. For the `new Random` ctor we find:

```csharp
public Random() =>
	// With no seed specified, if this is the base type, we can implement this however we like.
	// If it's a derived type, for compat we respect the previous implementation, so that overrides
	// are called as they were previously.
	_impl = GetType() == typeof(Random) ? new XoshiroImpl() : new CompatDerivedImpl(this);
```

What that means is that if we don't have a derived type (therefore the check `GetType() == typeof(Random)`)  we are using `XoshiroImpl` that is defined [here](https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/Random.Xoshiro256StarStarImpl.cs,82d6ed1c69a1ed98).

This bad boy is using [system calls internally](https://source.dot.net/#System.Private.CoreLib/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetRandomBytes.cs,466e9a485f6750aa):
```csharp
internal static partial class Interop
{
    internal static partial class Sys
    {
        [LibraryImport(Interop.Libraries.SystemNative, EntryPoint = "SystemNative_GetNonCryptographicallySecureRandomBytes")]
        internal static unsafe partial void GetNonCryptographicallySecureRandomBytes(byte* buffer, int length);
 
        // ...
 
    internal static unsafe void GetRandomBytes(byte* buffer, int length)
    {
        Sys.GetNonCryptographicallySecureRandomBytes(buffer, length);
    }
 
    // ....
}
```

So at best you are at the mercy of your underlying operating system. So let's continue and find out how thread safe we are here. We could easily check what `Random.Shared` does, because, as the author said, [it is thread safe](https://learn.microsoft.com/en-us/dotnet/api/system.random.shared?view=net-9.0).

> Provides a thread-safe Random instance that may be used concurrently from any thread.

[`Random.Shared`](https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/Random.cs,55) is using the following implementation:

```csharp
public static Random Shared { get; } = new ThreadSafeRandom();
````

What a surprise :D. Okay what is [`ThreadSafeRandom`](https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/Random.cs,5a7749f7e1d65e21)?

Basically:
```csharp
[ThreadStatic]
private static XoshiroImpl? t_random;

public ThreadSafeRandom() : base(isThreadSafeRandom: true) { }

private static XoshiroImpl LocalRandom => t_random ?? Create();
```

It is the same implementation, but using a `ThreadStatic` attribute. Keep that in mind as comes into play later.

## Is `new Random` now thread safe?

The answer it: It depends. And it depends on how you use it. For that let's dig out a beautiful blog post from Andrew lock from 2022: [*"Working with System.Random and threads safely in .NET Core and .NET Framework"*](https://andrewlock.net/building-a-thread-safe-random-implementation-for-dotnet-framework/).

He has a nice way of showing if we have threading issues (somewhat in the middle of the blog post). So let me "borrow" his code here:

```csharp
using System;
using System.Linq;
using System.Threading.Tasks;

// ? This isn't safe, don't do it ?
Random rng = new(); // create a shared Random instance
Parallel.For(0, 10, x =>  // run in parallel
{
    var numbers = new int[10_000];
    for (int i = 0; i < numbers.Length; ++i)
    {
        numbers[i] = rng.Next(); // Fetch 10,000 random numbers, to trigger the thread-safety issues
    }

    var numZeros = numbers.Count(x => x == 0); // how many issues were there?
    Console.WriteLine($"Received {numZeros} zeroes");
});
```

If you have threading issues, you get multiple zero counts. You can also run it as such (moving the new operator inside the loop):
```csharp
using System;
using System.Linq;
using System.Threading.Tasks;

// ? This isn't safe, don't do it ?
Parallel.For(0, 10, x =>  // run in parallel
{
	  Random rng = new(); // create a non-shared Random instance
    var numbers = new int[10_000];
    for (int i = 0; i < numbers.Length; ++i)
    {
        numbers[i] = rng.Next(); // Fetch 10,000 random numbers, to trigger the thread-safety issues
    }

    var numZeros = numbers.Count(x => x == 0); // how many issues were there?
    Console.WriteLine($"Received {numZeros} zeroes");
});
```

The second example is more what the author does. Remember the `ThreadLocalAttribute`. That is the difference between version 1 and 2. In version 2, we create new instances for each call. `ThreadLocal` has no play here. And guess what: No threading issues. In such case `Random.Shared` and `new Random()` would behave the same (except the useless allocations which you shouldn't have). 

Only version 1 is different, because in version 1 the `ThreadLocalAttribute` would tell that for each of the threads you would do a `new Random()` kind of thing.

## Conclusion

I guess I took a lot of your time to be just a dick and correct things, I probably shouldn't have to. But hey, hope you learned something.