前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java 17 更新(3):随机数生成器来了一波稳稳的增强

Java 17 更新(3):随机数生成器来了一波稳稳的增强

作者头像
bennyhuo
发布2021-09-30 10:37:18
1.4K0
发布2021-09-30 10:37:18
举报
文章被收录于专栏:BennyhuoBennyhuo

JDK 当中的随机数生成器其实对于普通开发者来讲基本够用,不过对于一些比较复杂的场景来讲,原有的类结构对扩展并不是很友好。

这一条更新来自:JEP 356: Enhanced Pseudo-Random Number Generators,相比之下,这一条实用多了。

我们都用过随机数,不过一般情况下我们很少去认真的对待随机数的具体结果,就好像它是真的随机一样。

代码语言:javascript
复制
var random = new Random(System.currentTimeMillis());
for (int i = 0; i < 10; i++) {
    System.out.println(random.nextInt());
}

除了 Random 类,JDK 当中还提供了另外几个随机数的成员:

  • ThreadLocalRandom:顾名思义,提供线程间独立的随机序列。它只有一个实例,多个线程用到这个实例,也会在线程内部各自更新状态。它同时也是 Random 的子类,不过它几乎把所有 Random 的方法又实现了一遍。
  • SplittableRandom:非线程安全,但可以 fork 的随机序列实现,适用于拆分子任务的场景。

ThreadLocalRandom 继承自 Random,而 SplittableRandom 与它俩则没什么实际的关系,因此如果我们在代码当中想要动态切换 Random 和 SplittableRandom 就只能定义两个成员,并且在用到的地方做判断:

Java 16

代码语言:javascript
复制
SplittableRandom splittableRandom = ...;
Random random = ...;

boolean useSplittableRandom = false;

...
    
if (useSplittableRandom) {
   nextInt = splittableRandom.nextInt();
} else {
    nextInt = random.nextInt();
}

而且如果想要自己扩展随机数的算法,也只能自己去实现,原有的定义方式缺乏一个统一的接口。

Java 17 为了解决这个问题,定义了几个接口:

这样我们就可以面向接口编程啦~

另外,尽管各个实现的细节不太一样,但思路基本上一致,因此老版本当中的几个随机数的类当中存在大量重复或者相似的代码。连 JDK 都存在 CV 代码的情况,那我们为了快速实现需求 CV 代码也不丢人,对不。

Java 17 把这些高度相似的逻辑抽了出来,搞了一个新的类:RandomSupport,又一个 3000 行的 Java 文件。

所以以前:

Java 16

代码语言:javascript
复制
// Random.java
public DoubleStream doubles() {
    return StreamSupport.doubleStream
        (new RandomDoublesSpliterator
         (this, 0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0),
         false);
}

// SplittableRandom.java
public DoubleStream doubles(long streamSize, double randomNumberOrigin,
                            double randomNumberBound) {
    if (streamSize < 0L)
        throw new IllegalArgumentException(BAD_SIZE);
    if (!(randomNumberOrigin < randomNumberBound))
        throw new IllegalArgumentException(BAD_RANGE);
    return StreamSupport.doubleStream
        (new RandomDoublesSpliterator
         (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
         false);
}

有相似的地方吧。我们再来看看 Java 17 的实现:

Java 17

代码语言:javascript
复制
// Random.java
public DoubleStream doubles() {
    return AbstractSpliteratorGenerator.doubles(this);
}

//SplittableRandom.java
private AbstractSplittableGeneratorProxy proxy;
...
public DoubleStream doubles() {
    return proxy.doubles();
}
...
private class AbstractSplittableGeneratorProxy extends AbstractSplittableGenerator {
    @Override
    public int nextInt() {
        return SplittableRandom.this.nextInt();
    }

    @Override
    public long nextLong() {
        return SplittableRandom.this.nextLong();
    }

    @Override
    public java.util.SplittableRandom split(SplittableGenerator source) {
        return new SplittableRandom(source.nextLong(), mixGamma(source.nextLong()));
    }
}

而这个 AbstractSplittableGenerator 就定义在 RandomSupport.java 当中,是 RandomSupport 一个内部类。

你以为这就没了?不是的。提案的说明当中提到,提案的目标不是实现很多的随机数产生算法,不过这次还是添加了一些常见的实现,所以你会在 JDK 17 当中看到多了一个模块:

这些实现都有自己的名字,用注解标注出来,例如:

代码语言:javascript
复制
@RandomGeneratorProperties(
        name = "L32X64MixRandom",
        group = "LXM",
        i = 64, j = 1, k = 32,
        equidistribution = 1
)
public final class L32X64MixRandom extends AbstractSplittableWithBrineGenerator { ... }

我们可以通过名字来获取它们的实例:

代码语言:javascript
复制
var random = RandomGenerator.of("L32X64MixRandom");
for (int i = 0; i < 10; i++) {
    System.out.println(random.nextInt());
}

好啦,关于随机数的更新又讲完啦。你不会又觉得这玩意没啥用吧。


本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-09-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Kotlin 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档