# 再谈随机数引起的阻塞问题

Java的随机数实现有很多坑，记录一下这次使用jdk1.8里新增的加强版随机数实现SecureRandom.getInstanceStrong() 遇到的问题。

-Djava.security.egd=file:/dev/./urandom


SecureRandom.getInstanceStrong();


"DubboServerHandler-xxx:20880-thread-1789" #28440 daemon prio=5 os_prio=0 tid=0x0000000008ffd000 nid=0x5712 runnable [0x000000004cbd7000]
at sun.security.provider.NativePRNG$RandomIO.readFully(NativePRNG.java:410) at sun.security.provider.NativePRNG$RandomIO.implGenerateSeed(NativePRNG.java:427)
- locked <0x00000000c03a3c90> (a java.lang.Object)
at sun.security.provider.NativePRNG$RandomIO.access$500(NativePRNG.java:329)
at sun.security.provider.NativePRNG$Blocking.engineGenerateSeed(NativePRNG.java:272) at java.security.SecureRandom.generateSeed(SecureRandom.java:522)  因为这个地方有加锁，locked <0x00000000c03a3c90>，所以其它线程调用到这里时会等待这个lock: "DubboServerHandler-xxx:20880-thread-1790" #28441 daemon prio=5 os_prio=0 tid=0x0000000008fff000 nid=0x5713 waiting for monitor entry [0x000000004ccd8000] java.lang.Thread.State: BLOCKED (on object monitor) at sun.security.provider.NativePRNG$RandomIO.implGenerateSeed(NativePRNG.java:424)
- waiting to lock <0x00000000c03a3c90> (a java.lang.Object)
at sun.security.provider.NativePRNG$RandomIO.access$500(NativePRNG.java:329)
at sun.security.provider.NativePRNG$Blocking.engineGenerateSeed(NativePRNG.java:272) at java.security.SecureRandom.generateSeed(SecureRandom.java:522)  去查 NativePRNG$Blocking代码，看到它的文档描述：

A NativePRNG-like class that uses /dev/random for both seed and random material. Note that it does not respect the egd properties, since we have no way of knowing what those qualities are.

Returns a SecureRandom object that was selected by using the algorithms/providers specified in the securerandom.strongAlgorithms Security property.

securerandom.strongAlgorithms=NativePRNGBlocking:SUN


On Linux:

1) when this value is “file:/dev/urandom” then the NativePRNG algorithm is registered by the Sun crypto provider as the default implementation; the NativePRNG algorithm then reads from /dev/urandom for nextBytes but /dev/random for generateSeed

2) when this value is “file:/dev/random” then the NativePRNG algorithm is not registered by the Sun crypto provider, but the SHA1PRNG system uses a NativeSeedGenerator which reads from /dev/random.

3) when this value is anything else then the SHA1PRNG is used with a URLSeedGenerator that reads from that source.

4) when the value is undefined, then SHA1PRNG is used with ThreadedSeedGenerator

5) when the code explicitly asks for “SHA1PRNG” and the value is either “file:/dev/urandom” or “file:/dev/random” then (2) also occurs

6) when the code explicitly asks for “SHA1PRNG” and the value is some other “file:” url, then (3) occurs

7) when the code explicitly asks for “SHA1PRNG” and the value is undefined then (4) occurs


In SHA1PRNG, there is a SeedGenerator which does various things depending on the configuration.

1. If java.security.egd or securerandom.source point to “file:/dev/random” or “file:/dev/urandom”, we will use NativeSeedGenerator, which calls super() which calls SeedGenerator.URLSeedGenerator(/dev/random). (A nested class within SeedGenerator.) The only things that changed in this bug was that urandom will also trigger use of this code path.

2. If those properties point to another URL that exists, we’ll initialize SeedGenerator.URLSeedGenerator(url). This is why “file:///dev/urandom”, “file:/./dev/random”, etc. will work.