¿Es seguro el subproceso de clase aleatorio?

110

¿Es válido compartir una instancia de la Randomclase entre varios subprocesos? ¿Y para llamar nextInt(int)desde múltiples hilos en particular?

Shcheklein
fuente
@Bala R, no, no estamos hablando del objeto Random de C # sino de Java.
Buhake Sindi
Ups. Lo siento, me perdí esa parte.
Bala R
Tenga cuidado con el uso de Random para obtener números en un entorno de subprocesos múltiples puede dar malos resultados. Tal vez no importe, pero si está haciendo algunas simulaciones, es bueno saberlo.
Maxence SCHMITT
14
Para otros lectores: hay una nueva clase con 1.7 nombrada java.util.concurrent.ThreadLocalRandom.
Jin Kwon

Respuestas:

66

Es seguro para subprocesos en el sentido de que aún generará números aleatorios cuando sea utilizado por varios subprocesos.

La implementación de Sun / Oracle JVM utiliza sincronizados y AtomicLong como semilla para mejorar la coherencia entre los subprocesos. Pero no parece estar garantizado en todas las plataformas en la documentación.

No escribiría su programa para requerir tal garantía, especialmente porque no puede determinar el orden en el que nextInt()se llamará.

Peter Lawrey
fuente
69
Se ha agregado una garantía en los documentos de Java 7: "Las instancias de java.util.Random son seguras para subprocesos". docs.oracle.com/javase/7/docs/api/java/util/Random.html
Matt R
8

Según la documentación, Math.random () garantiza que es seguro para su uso por varios subprocesos. Pero la clase Random no lo hace. Supongo que entonces tendrás que sincronizarlo tú mismo.

Vincent Mimoun-Prat
fuente
7

Sí, Random es seguro para subprocesos. el nextInt()método llama al next(int)método protegido que usa AtomicLong seed, nextseed(atomic long) para generar una siguiente semilla. AtomicLongse utiliza para la seguridad de subprocesos en la generación de semillas.

Buhake Sindi
fuente
6

Como se dijo, se guarda en subprocesos, pero puede ser aconsejable usarlo de java.util.concurrent.ThreadLocalRandomacuerdo con este artículo (enlace muerto). ThreadLocalRandom también es una subclase de Random, por lo que es compatible con versiones anteriores.

El artículo enlazado compararon los resultados de las diferentes clases de perfiles de azar: java.util.Random, java.util.concurrent.ThreadLocalRandom y java.lang.ThreadLocal<java.util.Random>. Los resultados mostraron que el uso de ThreadLocalRandom es más eficaz, seguido de ThreadLocal y Random con peor rendimiento.

seyfahni
fuente
4

No hay ninguna razón por la que varios subprocesos no puedan usar el mismo Random. Sin embargo, dado que la clase no es explícitamente segura para subprocesos y mantiene una secuencia de números pseudoaleatorios a través de la semilla. Varios subprocesos pueden terminar con el mismo número aleatorio. Sería mejor crear varios Randoms para cada hilo y sembrarlos de manera diferente.

EDITAR : Acabo de notar que la implementación de Sun usa AtomicLong, así que supongo que es seguro para subprocesos (como también lo señaló Peter Lawrey (+1)).

EDIT2 : OpenJDK también usa AtomicLong para la semilla. Como han dicho otros, todavía no es bueno confiar en esto.

alpian
fuente
3

Así es como manejé el problema sin asumir que Random usa variables atómicas. Todavía puede colisionar aleatoriamente si currentTime * thread ides igual en algún momento en el futuro, pero eso es lo suficientemente raro para mis necesidades. Para evitar realmente la posibilidad de colisiones, puede hacer que cada solicitud espere una marca de tiempo de reloj única.

/**
 * Thread-specific random number generators. Each is seeded with the thread
 * ID, so the sequence of pseudo-random numbers are unique between threads.
 */
private static ThreadLocal<Random> random = new ThreadLocal<Random>() {
    @Override
    protected Random initialValue() {
        return new Random(
            System.currentTimeMillis() *
            Thread.currentThread().getId());
    }
};
Ryan
fuente
¡Arriba! P: ¿es una (24*60*60*1000)parte significativa?
Jin Kwon
1
Sí, fue una mala solución. El resultado (24*60*60*1000)fue que un hilo con ID 12en xxxxxxxxxx045millis no se sembró de la misma manera que un hilo 22en xxxxxxxxxx035millis. Sin embargo, no tengo ninguna buena razón para suponer que los ID de subprocesos son incrementales, y no hay una buena razón para pensar que estoy creando subprocesos en momentos más aleatorios mañana que hoy. Simplifiqué el alg ahora y actualicé la descripción para identificar la deficiencia.
Ryan
0

La Randomclase no está configurada para que una instancia se utilice en varios subprocesos. Por supuesto, si hizo esto, probablemente aumentará la posibilidad de volverse impredecible y más cercano a números aleatorios . Pero dado que es un generador pseudoaleatorio, no veo por qué necesitarías compartir una instancia. ¿Existe algún requisito más específico?

Bebedero de Java
fuente