最近项目在发了一个版本之后,发现有个接口总是漏数据,于是通过增加日志进行定位和排查,最后定位到一个简单的for循环,如下图:
上午一行begin日志会打印,下面的end不会打印,而且没有异常和错误抛出。这就是一个简单的for循环,然后设置一下redis,太不符合逻辑科学了。
整个for循环里面可能出问题的代码只有3个点:
- 生成随机数序列化设置redis
凭直觉肯定没结果,只能在for循环里面增加日志,最终锁定问题出现在随机数生成的方法调用那一行。
后面通过jstack查看线程数一直在攀升,进入线程打印的堆栈信息,也展示到了这一行。
这一行是Sonar在扫描的时候给出的建议代码,回滚成原来的Random r = new Random解决问题。
后面再一次查SecureRandom.getInstanceStrong();这个方法时,才发现如下问题:
SecureRandom.getInstanceStrong(); 是jdk1.8里新增的加强版随机数实现
如果你的服务器在Linux操作系统上,这里的罪魁祸首是SecureRandom generateSeed()。它使用/dev/random生成种子。但是/dev/random是一个阻塞数字生成器,如果它没有足够的随机数据提供,它就一直等,这迫使JVM等待。键盘和鼠标输入以及磁盘活动可以产生所需的随机性或熵,但在一个服务器缺乏这样的活动时,可能会出现问题



