为什么 Random.Shared 是线程安全的
在多线程环境中使用 Random 类来生成伪随机数时,很容易出现线程安全问题。例如,当多个线程同时调用 Next 方法时,可能会出现种子被意外修改的情况,导致生成的伪随机数不符合预期。
为了避免这种情况,.NET 框架引入了 Random.Shared 属性。它返回一个特殊的 Random 实例,可以在多线程环境中安全地生成伪随机数。
代码示例
下面是一个示例代码,演示了 Random.Shared 属性的使用方法:
using System;
|
在上面的代码中,我们使用 Random.Shared 属性创建了一个新的 Random 实例,然后在两个不同的线程中分别调用它的 Next 方法生成伪随机数。由于 Random.Shared 属性是线程安全的,所以两个线程之间的访问不会发生冲突,可以正常生成伪随机数。
原理说明
Random.Shared 属性返回的 Random 实例内部实际上使用了 [ThreadStatic] 属性,来实现对种子的线程安全访问。
[ThreadStatic] 属性用于标识一个字段,表示该字段在每个线程中都有一个独立的值。例如,如果一个字段被标记为 [ThreadStatic],那么每个线程都会有一个单独的副本,它们之间互不影响。
举个例子,假设我们有一个类,它有一个 [ThreadStatic] 字段:
public class MyClass
|
在这个例子中,Counter 字段被标记为 [ThreadStatic],表示每个线程都有一个单独的副本。例如,当我们在两个不同的线程中访问 Counter 字段时,实际上访问的是两个不同的副本,它们之间互不影响。
下面是一个示例代码,演示了 [ThreadStatic] 属性的使用方法:
using System;
|
在上面的代码中,我们创建了两个新的 Task,分别用于访问 Counter 字段。由于 Counter 字段被标记为 [ThreadStatic],所以两个 Task 在不同的线程中执行,访问的是两个不同的副本。我们可以从输出结果看出,两个 Task 之间的修改不会影响到对方。
运行上面的代码可能会得到类似下面的样例结果:
Thread1: Counter = 1
|
可以看到,每个线程都会使用自己的 _counter 变量来记录递增的值,因此两个线程之间的值是不同的。
以上是 [ThreadStatic] 属性的使用方法。在 Random.Shared 属性的实现中,也采用了类似的方法,来实现种子的线程安全访问。由于每个线程都有一个单独的种子,所以它们之间互不影响,并且也不会发生线程安全问题。
使用建议
在多线程环境中,我们建议使用 Random.Shared 属性来生成伪随机数。它能够提供线程安全的保证,避免出现种子被意外修改的情况。
总结
通过使用 [ThreadStatic] 属性,.NET 框架实现了线程安全的 Random.Shared 属性。它允许我们在多线程环境中安全地生成伪随机数,而不用担心种子被意外修改的情况。
参考资料:
本文采用 Chat OpenAI 辅助注水浇筑而成,如有雷同,完全有可能。
- 本文链接: https://www.newbe.pro/ChatAI/Why-randome-shared-is-thread-safe/
- 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
- Newtonsoft 六个超简单又实用的特性,值得一试 【下篇】
- Newtonsoft 六个超简单又实用的特性,值得一试 【上篇】
- HashSet扩容机制在时间和空间上的浪费,远大于你的想象
- foreach 集合又抛经典异常了,这次一定要刨根问底
- C#9.0 终于来了,带你一起解读 nint 和 Pattern matching 两大新特性玩法
- C#9.0 终于来了,您还学的动吗? 带上VS一起解读吧!(应该是全网第一篇)
- MySql轻松入门系列——第二站 使用visual studio 对mysql进行源码级调试
- 字符串太占内存了,我想了各种奇思淫巧对它进行压缩
- MySql轻松入门系列——第一站 从源码角度轻松认识mysql整体框架图
- 自定义值类型一定不要忘了重写Equals,否则性能和空间双双堪忧
- 使用PInvoke互操作,让C#和C++愉快的交互优势互补
- 阿里短信回执.net sdk的bug导致生产服务cpu 100%排查
- List的扩容机制,你真的明白吗?
- BitArray虽好,但请不要滥用,又一次线上内存暴增排查
- 记一次排查线上程序内存的忽高忽低,又是大集合惹祸了
- 追了多年的开发框架,你还认识指针吗?
- 还不明白可空类型原理? 我可要挖到底了
- 不要把异常当做业务逻辑,这性能可能你无法承受
- 内存迟迟下不去,可能你就差一个GC.Collect
- 慎用ToLower和ToUpper,小心把你的系统给拖垮了