记录SecureRandom踩坑经历

背景

上周工作中有个问题耽搁了很长时间,打算写个博客记录一下,算是一个小复盘。

问题

我们公司共有三个测试环境,暂且称为test1、test2、test3环境。有一个服务发布在test3环境可以正常使用,没有任何报错,但是发布在test2环境就会报错。代码都是一样的,刚开始是怀疑配置有问题,仔细检查之后没有任何问题。后来借助arthas定位到了问题在于SecureRandom。也是因为这个事情,也专门写了一篇博客记录下。

SecureRandom

使用随机数的话,一般会像这样:

public void doSomethingCommon() {
          
   
  Random rand = new Random();  
  ...
}

但是呢,这样使用的话,sonar会给你一个告警:

Creating a new Random object each time a random value is needed is inefficient and may produce numbers which are not random depending on the JDK. For better efficiency and randomness, create a single Random, then store, and reuse it.

大意就是说不能每个方法都创建 Random生成随机数,因为效率太低,应该定义Random单例统一生成。并且明确建议使用SecureRandom.getInstanceStrong() 来初始化,就像这样:

private Random rand = SecureRandom.getInstanceStrong();

ok,照你说的改,改完之后就出现了上面的问题,test3环境是好的,test2就是不行,只有上了arthas才定位到问题所在,执行到 SecureRandom.getInstanceStrong() 方法后就线程就阻塞掉了,这就很拉胯了。

关于SecureRandom,讲的很清楚了,大概是因为SecureRandom在生成随机数的时候,会判断当前服务器环境的一些属性值,鼠标、键盘输入这些都算,所以就和环境有很强的相关性了,如果没有足够的环境属性用于生成随机数,就会一直等待,也就迫使JVM等待了。

源码中显示:

SecureRandom secureRandom = new SecureRandom();

会指定seed = 0,而sonar推荐的方式没有指定这个值,我猜差别应该是在这地方,总之new的方式不会导致阻塞,当然了,这是我猜的。

总之这种因为环境不同导致的问题,排查起来还是很糟心的。首先想吐槽下sonar,也是因为它的扫描和推荐才导致我排查这个了好久,其次呢也算吃一堑长一智,以后遇到这种问题也大概有个思路了,还有就是arthas又熟了一些,活到老学到老哈哈~~

参考资料:

经验分享 程序员 微信小程序 职场和发展