簡體   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