Допустимо ли разделять один экземпляр Random
класса между несколькими потоками? И, nextInt(int)
в частности, для вызова из нескольких потоков?
java.util.concurrent.ThreadLocalRandom
.
Допустимо ли разделять один экземпляр Random
класса между несколькими потоками? И, nextInt(int)
в частности, для вызова из нескольких потоков?
java.util.concurrent.ThreadLocalRandom
.
Ответы:
Он потокобезопасен в том смысле, что он все равно будет генерировать случайные числа при использовании несколькими потоками.
Реализация Sun / Oracle JVM использует synchronized и AtomicLong в качестве начального числа для улучшения согласованности между потоками. Но, похоже, это не гарантируется для всех платформ в документации.
Я бы не стал писать вашу программу, требующую такой гарантии, тем более что вы не можете определить порядок, в котором nextInt()
она будет вызвана.
Это потокобезопасный, хотя так было не всегда.
Видеть Http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6362070 для получения дополнительной информации.
Согласно документации, Math.random () гарантирует безопасность для использования несколькими потоками. Но класс Random - нет. Я предполагаю, что вам придется синхронизировать это самостоятельно.
Да, Random является потокобезопасным. nextInt()
метод вызывает защищенный next(int)
метод , который использует AtomicLong seed, nextseed
(атомный длинный) для создания следующего семени. AtomicLong
используется для обеспечения нитевой безопасности при генерации семян.
Как уже было сказано, это сохранение потока, но может быть разумно использовать в java.util.concurrent.ThreadLocalRandom
соответствии с этой статьей (ссылка мертва). ThreadLocalRandom также является подклассом Random, поэтому он обратно совместим.
В статье связанные между собой сравниваемых результаты различных классов случайных профилирование:
java.util.Random
,java.util.concurrent.ThreadLocalRandom
иjava.lang.ThreadLocal<java.util.Random>
. Результаты показали, что использование ThreadLocalRandom является наиболее эффективным, за ним следует ThreadLocal и хуже всего работает сам Random.
Нет причин, по которым несколько потоков не могут использовать одно и то же Random. Однако, поскольку класс не является явно потокобезопасным и поддерживает последовательность псевдослучайных чисел через начальное число. Несколько потоков могут иметь одно и то же случайное число. Было бы лучше создать несколько Random для каждого потока и по-разному их засеять.
РЕДАКТИРОВАТЬ : Я только что заметил, что реализация Sun использует AtomicLong, поэтому я предполагаю, что это потокобезопасный (как также отметил Питер Лоури (+1)).
EDIT2 : OpenJDK также использует AtomicLong для семени. Как уже говорили другие, полагаться на это по-прежнему нецелесообразно.
Вот как я решил проблему, не предполагая, что Random использует атомарные переменные. Он все еще может случайным образом столкнуться, если currentTime * thread id
в какое-то время будет одинаково, но это достаточно редко для моих нужд. Чтобы действительно избежать возможности коллизий, вы можете заставить каждый запрос ожидать уникальную временную метку часов.
/**
* 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)
часть значима?
(24*60*60*1000)
том, что поток с идентификатором 12
в xxxxxxxxxx045
миллисекундах не засевается так же, как поток 22
в xxxxxxxxxx035
миллисекундах. Однако у меня нет веских оснований предполагать, что идентификаторы потоков являются инкрементными, и нет веских причин думать, что завтра я создаю потоки в более случайное время, чем сегодня. Я упростил алгоритм и обновил описание, чтобы выявить недостаток.
Random
Класс не настроен для одного экземпляра , которые будут использоваться в нескольких потоках. Конечно, если вы это сделаете, вероятно, вы увеличите вероятность непредсказуемости и приближения к случайным числам. Но поскольку это псевдослучайный генератор, я не понимаю, зачем вам нужно делиться экземпляром. Есть ли более конкретные требования?