随机数发生器怎么用_用随机数发生器射击自己的脚

随机数发生器怎么用

这将不是解释随机数生成器毕竟不是那么随机的文章之一。 因此,您中的那些人希望获得有关如何破解老虎机,继续前进的指南,在这里什么也看不到。

相反,它是有关一个不太常见的锁争用问题的帖子,该问题隐藏在Java API的随机数生成器中。

要打开该主题,让我们开始研究如何在java.util.Random类中处理并发。 java.util.Random的实例是线程安全的。 但是,在线程之间并发使用同一java.util.Random实例是同步的,并且正如我们发现的那样,它倾向于触发影响应用程序性能的争用问题。

在您日常的日常企业应用程序中,这听起来似乎不是一个重要的问题–毕竟,您实际上有多少次实际执行了故意无法预测的事情? 相反,您只是在按照可预见的方式遵循业务规则。 我必须承认,尽管在某些情况下,这些业务规则比真正的随机种子生成算法所涉及的熵甚至更大,但这完全是另一回事。

但是魔鬼隐藏在细节中,在这种情况下,碰巧是java.util.Random的子类,即java.util.SecureRandom 。 此类,如名称所述,应在随机数生成器的结果必须是加密安全的情况下使用。 出于人类未知的原因,在通常不希望随机性的密码安全方面具有重要意义的情况下,已将该实现选择为许多常见API的主干。

我们通过密切关注锁争用检测解决方案的采用来亲身体验这个问题。 根据结果​​,通过看起来无辜的java.io.File.createTempFile()调用触发Java应用程序中最常见的锁定问题之一。 在后台,这种临时文件的创建依赖于SecureRandom来计算文件的名称。

private static final SecureRandom random = new SecureRandom();
static File generateFile(String prefix, String suffix, File dir) {
    long n = random.nextLong();
    if (n == Long.MIN_VALUE) {
        n = 0;      // corner case
    } else {
        n = Math.abs(n);
    }
    return new File(dir, prefix + Long.toString(n) + suffix);
}

然后,当调用nextLong时,SecureRandom最终调用其方法nextBytes() ,该方法定义为synced

synchronized public void nextBytes(byte[] bytes) {
    secureRandomSpi.engineNextBytes(bytes);
}

有人会说,如果我在每个线程中创建新的SecureRandom,我将不会遇到任何问题。 不幸的是,这并不是那么简单。 SecureRandom使用java.security.SecureRandomSpi的实现,无论如何最终都会争夺它(您可能会在Jenkins问题跟踪器中看到以下带有一些基准的bug讨论)

这与某些应用程序使用模式结合在一起(尤其是如果您有许多SSL连接依靠SecureRandom来实现其加密握手魔术),则有形成长期持久争用问题的趋势。

如果您可以控制源代码,则解决此问题的方法很简单–只需重建解决方案即可依靠java.util.ThreadLocalRandom进行多线程设计。 如果您坚持使用标准API,则解决方案可能会更加复杂,并且需要大量重构。

故事的道德启示? 并发很难。 尤其是在您的系统构建模块未考虑到这一点的情况下。 无论如何,我确实希望这篇文章至少从两个新库的诞生中拯救世界,在新库中,随机数生成器将成为竞争点。

翻译自: https://www.javacodegeeks.com/2015/03/shooting-yourself-in-the-foot-with-random-number-generators.html

随机数发生器怎么用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值