The problem on Stack Overflow is usually as follows: I use Random. Next to generate a Random number, but the method always returns the same value. This random number changes every time you run it, but this method produces many identical random numbers. The code is as follows: // Bad code! Do not use! For (int I = 0; I <100; I ++) {Console. writeLine (GenerateDigit ());}... static int GenerateDigit () {Random rng = new Random (); // Assume there 'd be more logic here really return rng. next (10);} what exactly happened? The explanation of the Random class is not a real Random number generator, but a pseudo Random number generator. Any Random instance has a certain number of Status values. When you call the Next method, the instance will return some seemingly Random data with these status values. Then change the internal status, and then you will be able to get the next set of seemingly random numbers. All of these are determined. If you use the same initial status value (which can be provided by seeds) to create a Random instance and call the same method of the instance, you will get the same data. So where is the error in our demo code? We create a new Random instance in each loop. Random's default constructor uses the current date and time as the seed. Before the internal current date and time change, you have generally executed a lot of code. Therefore, we have been repeatedly using the same seed (Note: The default seed of Random is the number of milliseconds from the last computer to the present, which is millisecond-level, so it is easy to have the same seed when multiple calls), and then get the same result repeatedly. What should we do? There are many solutions for this problem-some solutions are better than others. Let's first take a look at a solution. This solution is different from other solutions. Using the encrypted random number generator. NET Framework, there is a RandomNumberGenerator class, which is an abstract class. All the encrypted random number generators must inherit from this class. The framework itself provides a derived class: RNGCryptoServiceProvider. The main idea of encrypting a random number generator is that, even if it is a pseudo-random number generator, it does a lot of work to predict the random number generated by it. The built-in implementation uses many entropy values that can effectively represent the "noise" of your computer, which makes the random number unpredictable. (Note: The noise here may be unpredictable, such as the user's mouse track and the user's keyboard position.) "noise" may not only be used to generate a seed, it may also be used when the next random number is generated, so even if you know the current status, you still cannot predict the next result. Windows systems can also use randomness on specific hardware (for example, a hardware that can monitor radioactive isotope decay) to ensure the safety of random number generators. We will compare the Random class with the encrypted Random number generator if you have 10 Random. if you have enough computing power to return the results of Next (100), you may be able to crack the original seed value to predict the Next random value. The previously generated random values can also be obtained. If these mechanisms are used for some security or financial purposes, this may be disastrous. The encrypted Random number generator is generally slower than Random, but it is much better than Random to generate Random numbers that cannot be predicted independently. In many cases, the efficiency of the random number generator is not a problem, but a friendly interface (API) is a problem. The RandomNumberGenerator class is designed to generate random bytes and can only be in the byte format. The interfaces provided by the Random class are much more friendly. It allows the generation of a Random integer, Random floating point number, or some Random bytes. When using RandomNumberGenerator, I often find that I need to generate a random value in a range, it is difficult to obtain such a random value reliably and consistently from a random byte array. It is not impossible, but you must at least encapsulate an Adapter Class on RandomNumberGenerator ). In most cases, the pseudo-Random number generated by Random is enough, but be careful not to fall into the "traps" mentioned above ". Next let's take a look at how we can avoid "traps ". Repeat a single Random instance to fix "Many duplicate Random numbers". The key is to repeat the same Random instance. It sounds quite simple... For example, we can change the original code to this: // Somewhat better code... random rng = new Random (); for (int I = 0; I <100; I ++) {Console. writeLine (GenerateDigit (rng ));}... static int GenerateDigit (Random rng) {// Assume there 'd be more logic here really return rng. next (10);} Now our loop will print different numbers, but we have not finished it yet. What will happen if you call this code multiple times in a short time? We may still construct two Random instances with the same seed. Although the output numbers are different, we can easily get the same output twice. We have two ways to avoid this problem. The first solution is to use static fields to store the Random instance, and this instance is used everywhere. Another solution is to place the construction point of Random in a higher level. Of course, you will eventually reach the entry point of the program. In this way, we will only create a Random instance, and then upload it to each desired place. This is a good note (and can express dependencies well), but this solution does not work completely. If your code uses multiple threads, this will cause problems. The thread security problem Random is NOT thread security. This is indeed a big flaw, and we ideally have only one instance in the program and use it everywhere. But this cannot be done! If you use the same instance in multiple threads at the same time, it is likely to change its internal state to 0, so our Random instance will be useless. Similarly, there are two solutions to this problem. One instance is still used, but the locking method is used to ensure that only one thread is called at the same time. A random number generator can be used only after the lock is obtained for each call. We can encapsulate a layer for simple use by callers. However, in a system that frequently uses multiple threads, this may waste a lot of time waiting for locking. Another solution-one thread only uses one instance. What we need to do is to ensure that the instance we created will not reuse the same seed (that is, we cannot directly call the default no-argument constructor). This solution is relatively simple and clear. Fortunately, the ThreadLocal class added in. NET 4 can help us easily write a provider to ensure that each thread has a single instance. You only need to provide a simple Delegate to the ThreadLocal constructor to get a T instance through this delegate, and the next thing is.. NET Framework. In my example, I chose to use a seed variable and set its initialization value to Environment. tickCount (the same as the default no-argument constructor), and then auto-increment after each call, so that each thread can use different seeds. See the following code. This class is a static class with only one public method: GetThreadRandom. Designing it as a method rather than directly exposing attributes is mainly for convenience. In this way, where Random numbers are generated, you only need to reference the Random class and do not need to reference Func <Random>. If the type is only used for single-threaded operations, the Provider will call the delegate to obtain the instance and then reuse the instance. If the Provider is used by multiple threads, it will call the delegate every time to obtain the instance. ThreadLocal only creates one instance for each thread, and each Random instance uses a different seed. If you need to upload the method to the dependency, we can use a method to convert it: new TypeThatNeedsRandom (RandomProvider. getThreadRandom) code: using System; using System. threading; public static class RandomProvider {private static int seed = Environment. tickCount; private static ThreadLocal randomWrapper = new ThreadLocal () => new Random (Interlocked. increment (ref seed); public static Random GetThreadRandom () {return randomWrapper. value ;}} is simple, isn't it? This is because this class only pays attention to providing the correct Random instance, and does not care about the methods or things you call after getting the instance. Of course, this class may also be misused. For example, when a Random instance is obtained and used in a multi-threaded environment, this cannot be avoided, however, this class makes it easier for us to do the right thing.