O tópico da classe Random é seguro?

110

É válido compartilhar uma instância da Randomclasse entre vários threads? E chamar nextInt(int)de vários tópicos em particular?

Shcheklein
fonte
@Bala R, não, não estamos falando sobre o objeto Random do C #, mas do Java.
Buhake Sindi
opa. desculpe perdi essa parte.
Bala R
O cuidado de usar Random para obter números em um ambiente multithread pode gerar resultados ruins. Talvez não importe, mas se você estiver fazendo algumas simulações, é bom saber.
Maxence SCHMITT
14
Para outros leitores: há uma nova classe com 1.7 nomeado java.util.concurrent.ThreadLocalRandom.
Jin Kwon

Respostas:

66

É thread-safe no sentido de que ainda irá gerar números aleatórios quando usado por vários threads.

A implementação Sun / Oracle JVM usa synchronized e AtomicLong como seed para melhorar a consistência entre os threads. Mas isso não parece ser garantido em todas as plataformas na documentação.

Eu não escreveria seu programa para exigir tal garantia, especialmente porque você não pode determinar a ordem em que nextInt()será chamado.

Peter Lawrey
fonte
69
Uma garantia foi adicionada aos documentos do Java 7: "Instâncias de java.util.Random são threadsafe." docs.oracle.com/javase/7/docs/api/java/util/Random.html
Matt R
8

De acordo com a documentação, Math.random () garante que é seguro para uso por várias threads. Mas a classe Random não. Eu diria que então você terá que sincronizar isso sozinho.

Vincent Mimoun-Prat
fonte
7

Sim, Random é thread-safe. o nextInt()método chama o next(int)método protegido que usa AtomicLong seed, nextseed(comprimento atômico) para gerar uma próxima semente. AtomicLongé usado para segurança de thread na geração de sementes.

Buhake Sindi
fonte
6

Como disse, é thread save, mas pode ser sábio usar de java.util.concurrent.ThreadLocalRandomacordo com este artigo (link morto). ThreadLocalRandom também é uma subclasse de Random, portanto, é compatível com versões anteriores.

O artigo ligado comparou profiling resultados das diferentes classes aleatórios: java.util.Random, java.util.concurrent.ThreadLocalRandom e java.lang.ThreadLocal<java.util.Random>. Os resultados mostraram que o uso de ThreadLocalRandom tem maior desempenho, seguido por ThreadLocal e o próprio Random de pior desempenho.

Seyfahni
fonte
4

Não há razão para que vários tópicos não possam usar o mesmo Random. No entanto, uma vez que a classe não é explicitamente thread-safe e mantém uma sequência de números pseudo-aleatórios por meio da semente. Vários threads podem terminar com o mesmo número aleatório. Seria melhor criar vários Randoms para cada segmento e semeá-los de maneira diferente.

EDITAR : Acabei de notar que a implementação da Sun usa AtomicLong, então acho que é thread-safe (como também observado por Peter Lawrey (+1)).

EDIT2 : OpenJDK também usa AtomicLong para a semente. Como outros já disseram, ainda não é bom confiar nisso.

alpino
fonte
3

Veja como lidei com o problema sem presumir que Random usa variáveis ​​atômicas. Ele ainda pode colidir aleatoriamente se currentTime * thread idfor igual em algum momento no futuro, mas isso é raro o suficiente para minhas necessidades. Para realmente evitar a possibilidade de colisões, você pode fazer com que cada solicitação espere por um registro de data e hora exclusivo.

/**
 * 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
fonte
Acima! P: a (24*60*60*1000)parte é significativa?
Jin Kwon
1
Sim, foi uma solução suja. O (24*60*60*1000)era para que um thread com ID 12em xxxxxxxxxx045millis não fosse propagado da mesma forma que um thread 22em xxxxxxxxxx035millis. No entanto, não tenho nenhum bom motivo para supor que os IDs de thread sejam incrementais e não há um bom motivo para pensar que estou criando threads mais aleatoriamente amanhã do que hoje. Simplifiquei a alg agora e atualizei a descrição para identificar a deficiência.
Ryan
0

A Randomclasse não está configurada para uma instância a ser usada em vários threads. Claro, se você fez isso, provavelmente aumentará a possibilidade de se tornar imprevisível e mais próximo dos números aleatórios . Mas, como é um gerador pseudo-aleatório, não consigo ver por que você precisaria compartilhar uma instância. Existe um requisito mais específico?

Bebedor de Java
fonte