繁体   English   中英

SecureRandom stream 多线程的奇怪行为

[英]SecureRandom stream weird behavior with multiple threads

我正在尝试使用SecureRandom生成随机值,特别是它对流的支持。 理想情况下,这些值应该在恒定的基础上生成,因此 stream 可以是无限的:

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)。

如果我限制 stream 并删除distinct()操作,行为是相同的:

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

编辑:

另一方面,如果我避免使用 stream 并仅从每个线程调用SecureRandom.nextInt()则不会按预期观察到竞争条件。

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

我想知道为什么迭代器会改变行为? 特别是ints()方法的 Javadocs 指出“生成一个伪随机 int 值,就好像它是调用方法nextInt()的结果一样”

PS:当然我可以解决这个问题,但是同步线程获取下一个值。

虽然SecureRandom本身是线程安全的,但流不是。 整个 Streams API 被构建为由单个线程访问。 虽然中间操作可以并行执行,但它们必须从单个线程调用。

因此ints()及其迭代器都不是线程安全的。

所以你可以做的是为每个线程创建一个 stream。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM