É válido compartilhar uma instância da Random
classe entre vários threads? E chamar nextInt(int)
de vários tópicos em particular?
java.util.concurrent.ThreadLocalRandom
.
É válido compartilhar uma instância da Random
classe entre vários threads? E chamar nextInt(int)
de vários tópicos em particular?
java.util.concurrent.ThreadLocalRandom
.
Respostas:
É 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.
É thread-safe, embora nem sempre tenha sido.
Consulte http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6362070 para obter mais detalhes.
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.
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.
Como disse, é thread save, mas pode ser sábio usar de java.util.concurrent.ThreadLocalRandom
acordo 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
ejava.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.
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.
Veja como lidei com o problema sem presumir que Random usa variáveis atômicas. Ele ainda pode colidir aleatoriamente se currentTime * thread id
for 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());
}
};
(24*60*60*1000)
parte é significativa?
(24*60*60*1000)
era para que um thread com ID 12
em xxxxxxxxxx045
millis não fosse propagado da mesma forma que um thread 22
em xxxxxxxxxx035
millis. 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.
A Random
classe 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?