SecureRandom 线程安全吗?
Posted
技术标签:
【中文标题】SecureRandom 线程安全吗?【英文标题】:Is SecureRandom thread safe? 【发布时间】:2010-11-30 12:00:05 【问题描述】:SecureRandom
线程安全吗?也就是初始化之后,能否依赖对下一个随机数的访问是线程安全的?检查源代码似乎表明它是,this bug report 似乎表明它缺乏作为线程安全的文档是一个 javadoc 问题。有没有人确认它实际上是线程安全的?
【问题讨论】:
【参考方案1】:请参阅 Java 9 中修复的 https://bugs.openjdk.java.net/browse/JDK-8165115。
上面写着:
SecureRandom
对象可以安全地被多个并发使用 线程。SecureRandom
服务提供商可以宣传它是 通过将服务提供者属性“ThreadSafe”设置为线程安全的 注册提供程序时为“true”。否则,SecureRandom
类将同步访问以下SecureRandomSpi
方法:SecureRandomSpi.engineSetSeed(byte[])
,SecureRandomSpi.engineNextBytes(byte[])
,SecureRandomSpi.engineNextBytes(byte[], SecureRandomParameters)
,SecureRandomSpi.engineGenerateSeed(int)
,和SecureRandomSpi.engineReseed(SecureRandomParameters)
.
【讨论】:
【参考方案2】:是的,是的。它扩展了Random
,它总是有一个de facto线程安全实现,并且来自Java 7, explicitly guarantees threadsafety.
如果多个线程使用单个SecureRandom
,则可能会出现争用影响性能的情况。另一方面,初始化SecureRandom
实例可能相对较慢。最好是共享一个全局 RNG,还是为每个线程创建一个新的 RNG,这取决于您的应用程序。 ThreadLocalRandom
类可用作提供支持SecureRandom
的解决方案的模式。
【讨论】:
感谢您的更新。奇怪的是,该错误被标记为“将无法修复”。但他们还是修好了。哦,好吧,我不羡慕他们的错误数据库的大小。 初始化SecureRandom
不仅会很慢,而且可能会因为缺少熵而挂起
请记住 ThreadLocalRandom 非常容易破解,所以如果您打算将生成的值暴露给世界,请使用 SecureRandom 代替 jazzy.id.au/default/2010/09/20/…
我要在这里站出来说这个答案是不正确的。保证线程安全的 Random 契约对子类没有约束力。当然,记录的 Random 的所有其他属性都没有绑定到子类,所以我不明白为什么应该假设线程安全。
@JamesKPolk 未能保留超类型的属性将违反可替换性原则。【参考方案3】:
SecureRandom
的当前实现是线程安全的,特别是 nextBytes(bytes[])
和 setSeed(byte[])
这两个变异方法是同步的。
好吧,据我所知,所有变异方法最终都通过这两种方法进行路由,SecureRandom
覆盖了Random
中的一些方法以确保这一点。哪个可行,但如果将来更改实施,可能会很脆弱。
最好的解决方案是先在SecureRandom
实例上手动同步。这意味着每个调用堆栈都会在同一个对象上获得两个锁,但这在现代 JVM 上通常非常便宜。也就是说,显式同步自己并没有太大的危害。例如:
SecureRandom rnd = ...;
byte[] b = new byte[NRANDOM_BYTES];
synchronized (rnd)
rnd.nextBytes(b);
【讨论】:
至少在 JDK 10 中,SecureRandom 是基于提供程序的,并检查提供程序是否是线程安全的,如果不是,则仅在 nextBytes 中同步。 Java 8 中的java.security.SecureRandom#nextBytes
未同步。您能否指定您在哪个 Java 版本中找到了同步的#nextBytes
?。以上是关于SecureRandom 线程安全吗?的主要内容,如果未能解决你的问题,请参考以下文章
java priorityblockingqueue 线程安全吗