Estoy tratando de generar valores aleatorios usando SecureRandom , específicamente su soporte de flujos. Idealmente, los valores deberían generarse de forma constante, por lo que la secuencia podría ser infinita:
SecureRandom secureRandom = new SecureRandom(); Iterator<Integer> idIterator = secureRandom.ints().distinct().iterator(); La documentación establece que "los objetos SecureRandom son seguros para su uso por múltiples subprocesos simultáneos". Sin embargo, cuando varios subprocesos recuperan el siguiente valor del iterador, aparece un error en (al menos) uno de los subprocesos que parece deberse a una condición de carrera:
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)Cuando ejecuto el código varias veces, a veces obtengo otro tipo de excepción (NullPointerException).
El comportamiento es el mismo si limito el flujo y elimino la operación distinct() :
secureRandom.ints().limit(100).iterator();EDITAR:
Por otro lado, si evito usar una transmisión y solo llamo a SecureRandom.nextInt() desde cada subproceso, no se observa ninguna condición de carrera como se esperaba.
Thread t1 = new Thread(() -> secureRandom.nextInt()); Thread t2 = new Thread(() -> secureRandom.nextInt()); t1.start(); t2.start(); // code is thread-safe Me pregunto por qué el iterador cambia de comportamiento. Especialmente que los Javadocs del método ints ints() establecen que "se genera un valor int pseudoaleatorio como si fuera el resultado de llamar al método nextInt() " .
PD: Por supuesto que puedo solucionar esto pero sincronizando los hilos adquiriendo el siguiente valor.
Si bien SecureRandom en sí mismo es seguro para subprocesos, las transmisiones no lo son. Toda la API de Streams fue construida para ser accedida por un solo hilo. Si bien las operaciones intermedias pueden ejecutarse en paralelo, deben llamarse desde un único subproceso.
Por lo tanto, ni ints() ni su iterador son seguros para subprocesos.
Entonces, lo que puede hacer es crear una transmisión por hilo.
Thread t1 = new Thread(() -> secureRandom.ints().distinct().iterator().next()); Thread t2 = new Thread(() -> secureRandom.ints().distinct().iterator().next()); t1.start(); t2.start();