楼主今天兴高采烈的在部署环境,下载 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. 源码分析
我们通过堆栈信息一步步跟进源码查看,
从方法 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/