securerandom流行为

cbjzeqam  于 2021-07-07  发布在  Java
关注(0)|答案(1)|浏览(434)

我试着用 SecureRandom ,特别是它对流的支持。理想情况下,应在恒定的基础上生成值,因此流可以是无限的:

SecureRandom secureRandom = new SecureRandom();
Iterator<Integer> idIterator = secureRandom.ints().distinct().iterator();

文件上说 SecureRandom 对象可由多个并发线程安全使用。“但是,当多个线程从迭代器检索下一个值时,我在其中一个线程中(至少)发现一个错误,该错误似乎是由于争用条件引起的:

Thread t1 = new Thread(() -> idIterator.next());
Thread t2 = new Thread(() -> idIterator.next());
t1.start();
t2.start();

Exception in thread "Thread-1" java.lang.IllegalStateException: source already consumed or closed
    at java.base/java.util.stream.AbstractPipeline.sourceSpliterator(AbstractPipeline.java:409)
    at java.base/java.util.stream.AbstractPipeline.lambda$spliterator$0(AbstractPipeline.java:367)
    at java.base/java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.init(StreamSpliterators.java:142)
    at java.base/java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.doAdvance(StreamSpliterators.java:157)
    at java.base/java.util.stream.StreamSpliterators$IntWrappingSpliterator.tryAdvance(StreamSpliterators.java:358)
    at java.base/java.util.Spliterators$2Adapter.hasNext(Spliterators.java:726)
    at java.base/java.util.Spliterators$2Adapter.nextInt(Spliterators.java:732)
    at java.base/java.util.PrimitiveIterator$OfInt.next(PrimitiveIterator.java:128)
    at java.base/java.util.PrimitiveIterator$OfInt.next(PrimitiveIterator.java:86)
    at example.Example.foo(Example.java:39)

当我多次运行代码时,有时会遇到另一种异常(nullpointerexception)。
如果我限制流并删除 distinct() 操作:

secureRandom.ints().limit(100).iterator();

编辑:
另一方面,如果我避免使用流而只调用 SecureRandom.nextInt() 从每个线程,没有观察到预期的争用条件。

Thread t1 = new Thread(() -> secureRandom.nextInt());
Thread t2 = new Thread(() -> secureRandom.nextInt());
t1.start();
t2.start(); // code is thread-safe

我想知道迭代器为什么会改变行为?尤其是 ints() 方法声明“生成一个伪随机int值,就好像它是调用该方法的结果一样 nextInt() ".
p、 s:当然我可以解决这个问题,但是同步线程获取下一个值。

zpf6vheq

zpf6vheq1#

SecureRandom 它本身是线程安全的,而流则不是。整个streams api构建为由单个线程访问。虽然中间操作可以并行执行,但它们必须从单个线程调用。
因此两者都不是 ints() 它的迭代器也不是线程安全的。
因此,您可以做的是,为每个线程创建一个流。

Thread t1 = new Thread(() -> secureRandom.ints().distinct().iterator().next());
Thread t2 = new Thread(() -> secureRandom.ints().distinct().iterator().next());
t1.start();
t2.start();

相关问题