SecureRandom 线程安全吗?

SecureRandom线程安全吗?也就是说,在初始化它之后,是否可以依赖对下一个随机数的访问来保证线程安全?检查源代码似乎可以看出来,而且 这个漏洞报告似乎表明它缺乏作为线程安全的文档是一个 javadoc 问题。有人确认它实际上是线程安全的吗?

25444 次浏览

Yes, it is. It extends Random, which always had a de facto threadsafe implementation, and, from Java 7, explicitly guarantees threadsafety.

If many threads are using a single SecureRandom, there might be contention that hurts performance. On the other hand, initializing a SecureRandom instance can be relatively slow. Whether it is best to share a global RNG, or to create a new one for each thread will depend on your application. The ThreadLocalRandom class could be used as a pattern to provide a solution that supports SecureRandom.

The current implementation of SecureRandom is thread safe, specifically the two mutating methods nextBytes(bytes[]) and setSeed(byte[]) are synchronized.

Well, as far as I've been able to tell, all mutating methods are eventually routed through those two methods, and SecureRandom overrides a few methods in Random to ensure that. Which works but could be brittle if the implementation is changed in the future.

The best solution is to manually synchronize on the SecureRandom instance first. This means each call stack will acquire two locks on the same object, but that is usually very cheap on modern JVMs. That is, there is not much harm in explicitly synchronizing yourself. For example:

    SecureRandom rnd = ...;


byte[] b = new byte[NRANDOM_BYTES];
synchronized (rnd) {
rnd.nextBytes(b);
}

Please see https://bugs.openjdk.java.net/browse/JDK-8165115 which was fixed in Java 9.

It says:

SecureRandom objects are safe for use by multiple concurrent threads. A SecureRandom service provider can advertise that it is thread-safe by setting the service provider attribute "ThreadSafe" to "true" when registering the provider. Otherwise, the SecureRandom class will synchronize access to the following SecureRandomSpi methods: SecureRandomSpi.engineSetSeed(byte[]), SecureRandomSpi.engineNextBytes(byte[]), SecureRandomSpi.engineNextBytes(byte[], SecureRandomParameters), SecureRandomSpi.engineGenerateSeed(int), and SecureRandomSpi.engineReseed(SecureRandomParameters).