偶遇 JDK 1.8 还未修复的 SecureRandom.getInstance("SHA1PRNG") 之 bug

楼主今天兴高采烈的在部署环境,下载 JDK,打包项目,上传至服务器。

配置 JDK ,打包上传项目楼主就不在这里重复了,读者自行解决哈!

 

1. 启动项目

java -jar xxxx.jar 

令楼主没有想到的是:程序卡主了,卡在了数据库建立连接的位置。(查看方法方式: jstack <pid> 即可)

 

2. 堆栈信息

由于是项目刚一启动,初始化数据库连接池,并没有太多的线程堆栈。这里我贴一下我遇到的主要问题的堆栈信息:


"restartedMain" #11 prio=5 os_prio=0 tid=0x00007f4430002800 nid=0x65b0 runnable [0x00007f447837a000]
   java.lang.Thread.State: RUNNABLE
	at java.io.FileInputStream.readBytes(Native Method)
	at java.io.FileInputStream.read(FileInputStream.java:255)
	at sun.security.provider.SeedGenerator$URLSeedGenerator.getSeedBytes(SeedGenerator.java:539)
	at sun.security.provider.SeedGenerator.generateSeed(SeedGenerator.java:144)
	at sun.security.provider.SecureRandom$SeederHolder.<clinit>(SecureRandom.java:203)
	at sun.security.provider.SecureRandom.engineNextBytes(SecureRandom.java:221)
	- locked <0x00000000d6eb8930> (a sun.security.provider.SecureRandom)
	at java.security.SecureRandom.nextBytes(SecureRandom.java:468)
	at oracle.security.o5logon.O5Logon.a(Unknown Source)
	at oracle.security.o5logon.O5Logon.<clinit>(Unknown Source)
	at oracle.jdbc.driver.T4CTTIoauthenticate.<init>(T4CTTIoauthenticate.java:566)
	at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:370)
	at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:546)
	at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:236)
	at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32)
	at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:521)

或许你会问我,为什么你要定位到这个线程?主要是因为道友经过好几次 jstack 操作,发现该线程一直都停留在该位置,这就足以说明这个线程是当前线程!

 

3. 分析堆栈信息

从上面的堆栈信息中,我们可以得知那些信息?

  • 当前线程名称为 : restartedMain
  • 当前线程状态为: RUNNABLE
  • 当前线程 ID: 0x00007f4430002800
  • native 线程 ID: 0x65b0
  • 当前运行位置 : at java.io.FileInputStream.readBytes(Native Method)

通过分析堆栈,想必读取文件不会有什么问题,我们往线程堆栈的上层追踪。目标点落在 

    at sun.security.provider.SeedGenerator$URLSeedGenerator.getSeedBytes(SeedGenerator.java:539)

很明显,这里是  JDK 源码的调用,接下来打卡 jdk 源码进行查看!

 

 

4. 源码分析

我们通过堆栈信息一步步跟进源码查看,

e9afe62c97833d39aa6dbf5cd4b804b5644.jpg

5430096c82f996f53aca5e5ef2bcc87189f.jpg

从方法  nextBytes 上来看,他调用这个是为了:生成用户指定的随机字节数。好吧,那就是它在生成的时候,需要读取某个文件来生成随机数。

 

5. 写个测试验证想法

[ryan@ryanmacbook ~]$ vim HelloWorld.java 
import java.security.SecureRandom;

class HelloWorld {

    public static void main(String args[]) throws Exception {

        byte[] bytes = new byte[32];

        SecureRandom.getInstance("SHA1PRNG").nextBytes(bytes);

        System.out.println("SourceRandom nextBytes : " + new String(bytes));
    }
}

紧接着执行

javac HelloWorld.java

这个要是读者你不会,那你就放弃java吧,java 界可能不适合你。

接下来执行 

java HelloWorld

执行后,,的结果是 

[ryan@ryanmacbook ~]$ java HelloWorld


^C
[ryan@ryanmacbook ~]$

卡住了,楼主强制 kill 了。

 

说明我们的问题点就是这里。

 

接下来,解决办法是啥?你要问楼主楼主也不知道,咋办?上百度呗,百度都不会用的程序员不是好程序员:

 

6. 解决办法

最后的解决办法就是 ,在项目启动的时候,修改 java.security.egd,通过如下方式,专业术语叫做    熵池策略   

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

问题的本质还是 Oracle 驱动类中调用了 SecureRandom.nextBytes() 。楼主还没来得及看其他驱动程序是否也有这个问题,当然也不排除与操作系统有关系。待验证其他操作系统后,再补充!

 

果断成功!

 

道友查了下,说是 JVM 的 bug , 在收集噪点的时候没有收集全导致的。如果你的也有遇到这样的问题,时而可用,时而不可用,那就是噪点收集的问题。

 

[参考链接] http://ifeve.com/jvm-random-and-entropy-source/

 

 

 

 

转载于:https://my.oschina.net/Rayn/blog/3052769

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值