前情提要:公司新引入了sonar对代码监测,由此根据sonar提出的建议修改了生成随机数的Random类。
修改前:
1 Random random = new Random(); 2 int num = random.nextInt(200); 3 System.out.println("生成随机数num=" + num);
修改后:
1 int num = 200; 2 3 try { 4 Random random = SecureRandom.getInstanceStrong(); 5 num = random.nextInt(200); 6 } catch (Exception ex) { 7 logger.error("生成随机数失败:" + ex.getMessage()); 8 } 9 10 System.out.println("生成随机数num=" + num);
修改完之后,运行了大概1天还是2天,后面有人反馈调用失败,实际是超时。
查询后台发现:调用的接口执行时间都在1分钟两分钟以上,每次都运行超时。打印的也都是num=200,随机数每次都是200,这才怀疑可能是之前根据sonar建议改过造成的。
但是在windows的测试案例里跑,两段代码并没有什么不一样,执行效果都挺快。带着试一试的心态修改了代码,部署到Linux机器上,问题终于迎刃而解。
后面在网上查询资料发现:(摘取其中的一段)
1 如果你的服务器在Linux操作系统上,这里的罪魁祸首是SecureRandom generateSeed()。 2 它使用/dev/random生成种子。但是/dev/random是一个阻塞数字生成器,如果它没有足够的随机数据提供,它就一直等,这迫使JVM等待。 3 键盘和鼠标输入以及磁盘活动可以产生所需的随机性或熵。但在一个服务器缺乏这样的活动,可能会出现问题。
有2种解决方案:
1. 在Tomcat环境中解决:
可以通过配置 JRE 使用非阻塞的 Entropy Source:
在 catalina.sh 中加入这么一行:-Djava.security.egd=file:/dev/./urandom 即可。
2. 在 JVM 环境中解决(本人使用此方法):
打开jdk安装路径 $JAVA_PATH/jre/lib/security/java.security 这个文件,找到下面的内容:
securerandom.source=file:/dev/random 替换成:securerandom.source=file:/dev/./urandom
// 以上引用自:http://www.manongjc.com/detail/18-lpszfgoaxerlvil.html
当然,除了以上2种解决方案外,你还可以不使用SecureRandom。