用线程安全随机数解决Random在多线程中随机性重复的问题

        在.NET中,随机数一般是用Random来获取,但是当在多任务的并行化编程时,问题就出现了。

因为Random是基于时间作为种子来生成伪随机数的,而如果程序在多核并行时,

在同一时间内的多个核中取到的时间是一样的,这样一来,生成的伪随机数就有可能会有一样的。

如果业务需求中需要不可重复的随机数,那么这后果将会相当严重,

所以必须采取一种新的方式来获取线程安全的伪随机数。

下面是摘自《.NET Parallel Extensions》中的一段关于线程安全随机数生成的类,也可参看http://code.msdn.microsoft.com/Samples-for-Parallel-b4b76364/sourcecode?fileId=44488&pathId=1352203765。
 

 

 

 

 

这个类ThreadSafeRandom继承自Random,所以可以像Random一样使用。

这里边关键用到了几个技术点:
1、RNGCryptoServiceProvider的加密随机生成器,再用其中的强随机序列的方法GetBytes来实现随机。
2、使用ThreadLocal来懒惰初使化(Lazy-Initialize)随机数的实例。因为ThreadLocal是针对于每一个线程的线程安全类,是线程的本地存储形式。如果同一个线程多次初始化ThreadLocal,那么得到的实例将会是一样的。因为如果一个线程已经初始化了该实例之后( ThreadSafeRandom safeRandom = new ThreadSafeRandom()),该线程后面继续初始化(再次调用 ThreadSafeRandom safeRandom = new ThreadSafeRandom())是不会再初始化一次,而是会返回之前的实例(有点像单件模式)。不过,这也带来了另一个问题,如果就是要在线程中不断产生新的实例时,这种做法就变的不合适了,不悉采用变通或者其他做法。
下面是关于Random和ThreadSafeRandom测试的实例


using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

namespace Chapter11_Console

{

    public class RadomTest

    {

        #region Run Function

        public static void Run()

        {

            Console.WriteLine("Started!");

 

            var sw = Stopwatch.StartNew();

            int normalRandomSameCount = randomSerial(generateNormalRadoms);

            Console.WriteLine("Normal Random Same Count:{0}, Consume Time:{1}", normalRandomSameCount, sw.Elapsed.ToString());

 

            sw.Restart();

            int threadSafeRandomSameCount = randomSerial(generateThreadSafeRadoms);

            Console.WriteLine("Thread Safe Random Same Count:{0}, Consume Time:{1}", threadSafeRandomSameCount, sw.Elapsed.ToString());

 

            Console.WriteLine("Completed!");

            Console.ReadLine();

        }

 

        private static int randomSerial(Func<int, List<int>> generateRadoms)

        {

            int randomCount = 100000;

            Task<List<int>>[] tasks = new Task<List<int>>[2];

            for (int i = 0; i < tasks.Length; i++)

            {

                tasks[i] = Task.Factory.StartNew(() =>

                {

                    return generateRadoms(randomCount);

                });

            }

            Task.WaitAll(tasks);

            int sameCount = 0;

            Task finalTask = Task.Factory.StartNew(() =>

            {

                for (int i = 0; i < randomCount; i++)

                {

                    if (tasks[0].Result[i] == tasks[1].Result[i])

                    {

                        sameCount++;

                    }

                }

            });

            finalTask.Wait();

            return sameCount;

        }

 

        private static List<int> generateNormalRadoms(int randomCount)

        {

            List<int> randoms = new List<int>();

            for (int i = 0; i < randomCount; i++)

            {

                Random random = new Random();

                randoms.Add(random.Next());

            }

            return randoms;

        }

 

        private static List<int> generateThreadSafeRadoms(int randomCount)

        {

            List<int> randoms = new List<int>();

            for (int i = 0; i < randomCount; i++)

            {

                ThreadSafeRandom safeRandom = new ThreadSafeRandom();

                randoms.Add(safeRandom.Next());

            }

            return randoms;

        }

        #endregion

    }

}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Random类是Java用于生成随机数的一个工具类。它可以生成伪随机数序列,可以用于各种需要随机数的场景,比如游戏、密码生成等。 要使用Random类,首先需要创建一个Random对象。可以使用无参构造方法创建一个默认的Random对象,也可以使用带有种子参数的构造方法创建一个指定种子的Random对象。种子是一个长整型数值,用于初始化随机数生成器的起始状态。 一旦创建了Random对象,就可以使用它的方法来生成随机数。常用的方法有: 1. nextInt():生成一个int类型的随机数。 2. nextDouble():生成一个double类型的随机数。 3. nextBoolean():生成一个boolean类型的随机数。 4. nextFloat():生成一个float类型的随机数。 5. nextLong():生成一个long类型的随机数。 下面是一个示例代码,演示如何使用Random类生成随机数: ```java import java.util.Random; public class RandomExample { public static void main(String[] args) { Random random = new Random(); int randomNumber = random.nextInt(100); // 生成0到99之间的随机整数 System.out.println("随机整数:" + randomNumber); double randomDouble = random.nextDouble(); // 生成0.0到1.0之间的随机小数 System.out.println("随机小数:" + randomDouble); boolean randomBoolean = random.nextBoolean(); // 生成随机的布尔值 System.out.println("随机布尔值:" + randomBoolean); } } ``` 需要注意的是,Random类生成的是伪随机数,也就是说它们是通过算法计算得到的,并不是真正的随机数。如果需要更高质量的随机数,可以考虑使用SecureRandom类。此外,在多线程环境下使用Random类时,需要注意线程安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值