![](/img/trans.png)
[英]notify and notifyall showing weird behavior to wait of multiple threads
[英]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.