C# 在.Net中,随机数据的并发性问题?

C# 在.Net中,随机数据的并发性问题?,c#,.net,concurrency,random,C#,.net,Concurrency,Random,我在调试一个类时遇到了一些问题,在Random类中遇到了一些问题,当几个线程从单个实例调用一个方法时 出于某种奇怪的原因,似乎如果我不阻止并发访问,通过同步被调用的方法,我的随机实例就会开始运行。。。随机的(但在坏的意义上) 在下面的示例中,我创建了数百个线程,它们重复调用单个随机对象。当我运行它时,我有时(不总是,但几乎)得到明显错误的结果。如果我取消对Synchronized方法注释的注释,则问题永远不会发生 using System; using System.Threading; usi

我在调试一个类时遇到了一些问题,在Random类中遇到了一些问题,当几个线程从单个实例调用一个方法时

出于某种奇怪的原因,似乎如果我不阻止并发访问,通过同步被调用的方法,我的随机实例就会开始运行。。。随机的(但在坏的意义上)

在下面的示例中,我创建了数百个线程,它们重复调用单个随机对象。当我运行它时,我有时(不总是,但几乎)得到明显错误的结果。如果我取消对
Synchronized
方法注释的注释,则问题永远不会发生

using System;
using System.Threading;
using System.Runtime.CompilerServices;
namespace testRandom {

    class RandTest  {
        static int NTIMES = 300;

        private long ac=0;

        public void run() { // ask for random number 'ntimes' and accumulate
            for(int i=0;i<NTIMES;i++) {
                ac+=Program.getRandInt();
                System.Threading.Thread.Sleep(2);
            }
        }

        public double getAv() { 
            return ac/(double)NTIMES; // average
        }
    }

    class Program
    {

        static Random random = new Random();
        static int MAXVAL = 256;
        static int NTREADS = 200;

        //[MethodImpl(MethodImplOptions.Synchronized)]
        public static int getRandInt() { 
            return random.Next(MAXVAL+1); // returns a value between 0 and MAXVAL (inclusive)
        }

        public static void Main(string[] args)      {
            RandTest[] tests = new RandTest[NTREADS];
            Thread[] threads = new Thread[NTREADS];
            for(int i=0;i<NTREADS;i++)  {
                tests[i]= new RandTest();
                threads[i] = new Thread(new ThreadStart(tests[i].run));
            }
            for(int i=0;i<NTREADS;i++)  threads[i].Start();
            threads[0].Join();
            bool alive=true;
            while(alive) { // make sure threads are finished
                alive = false;
                for(int i=0;i<NTREADS;i++)  { if(threads[i].IsAlive) alive=true; }
            }
            double av=0;
            for(int i=0;i<NTREADS;i++)  av += tests[i].getAv();
            av /= NTREADS;
            Console.WriteLine("Average:{0, 6:f2}   Expected:{1, 6:f2}",av,MAXVAL/2.0);

            Console.Write("Press any key to continue . . . ");
            Console.ReadKey(true);
        }
    }
}
这是已知的问题吗?在没有同步的情况下从多个线程调用随机对象是否不正确


更新:根据答案,文档声明随机方法不是线程安全的-这是罪过,我应该读到这一点。也许我以前读过这篇文章,但并不认为它如此重要——有人可能(草率地)认为,在两个线程同时进入同一个方法的罕见事件中,可能发生的最坏情况是这些调用得到错误的结果——如果我们不太关心随机数的质量,这并不是什么大问题。。。但是问题确实是灾难性的,因为对象处于不一致的状态,并且从该状态返回的值一直是零——正如前面提到的。

Random类不是线程安全的

从:

尝试实现该属性,而不是同步将导致所有线程阻塞

出于某种奇怪的原因

这并不奇怪-
Random
不是线程安全的


这是一种痛苦,但这就是生活。请参阅my以了解更多信息,以及如何在多个线程中为每个线程创建一个实例的建议,同时防止在多个线程中使用同一种子启动。

Random不能保证线程安全:除非它是公共静态的。

不幸的是,这是正确的,使用Random类时必须小心

以下是关于此主题的两篇博文,其中包含更多详细信息、评论和代码示例:


这种行为最糟糕的部分是它只是停止工作(即一旦出现问题,'random.Next….'方法的返回值为0)

为了澄清:“public static”指的是随机类的方法/属性,而不是随机对象本身谢谢。我仍然感到惊讶的是,这个问题看起来是如此的灾难性——我本以为一些随机值对一些并发调用来说是“错误的”,但似乎随机对象完全被搞砸了,从那时起它返回的是胡说八道。另见Jon的文章,除非文档说明了相反的情况,否则您不能假设任何类都支持多线程访问单个实例。“它只是停止工作”为什么这是最糟糕的部分?在我看来,这是最好的部分。否则你就不会注意到你的代码被破坏了。“我不得不说,我感觉有很多安全漏洞是由这种行为造成的”这些漏洞并不是因为缺乏线程安全性,而是因为首先使用了
Random
。您应该对所有与安全相关的内容使用加密rng。
Average: 78.98   Expected:128.00
Press any key to continue . . .
Any instance members are not guaranteed to be thread safe