Является ли случайный класс потоком безопасным?
Можно ли использовать один экземпляр класса Random
между несколькими потоками? И вызвать nextInt(int)
из нескольких потоков в частности?
Ответы
Ответ 1
Он потокобезопасен в том смысле, что он будет генерировать случайные числа при использовании несколькими потоками.
Реализация JVM Sun/Oracle использует синхронизированные и AtomicLong в качестве семян для улучшения согласованности потоков. Но, похоже, он не защищен на всех платформах документации.
Я бы не написал вашу программу, чтобы требовать такую гарантию, тем более, что вы не можете определить порядок, в котором будет вызываться nextInt()
.
Ответ 2
Это потокобезопасный, хотя это не всегда.
Подробнее см. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6362070.
Ответ 3
В соответствии с документацией Math.random() гарантирует его безопасность для использования несколькими потоками. Но класс Random не имеет. Я бы предположил, что вам придется синхронизировать это самостоятельно.
Ответ 4
Да, Random является потокобезопасным. метод nextInt()
вызывает защищенный метод next(int)
, который использует AtomicLong seed, nextseed
(атомный длинный) для генерации следующего семпла. AtomicLong
используется для обеспечения безопасности потоков при генерации семян.
Ответ 5
Как уже говорилось, это сохранение потока, но может быть разумно использовать java.util.concurrent.ThreadLocalRandom
соответствии с этой статьей (ссылка недействительна). ThreadLocalRandom также является подклассом Random, поэтому он обратно совместим.
В статье сравнивались результаты профилирования различных классов Random: java.util.Random
, java.util.concurrent.ThreadLocalRandom
и java.lang.ThreadLocal<java.util.Random>
. Результаты показали, что наиболее эффективным является использование ThreadLocalRandom, за которым следует ThreadLocal и худшее выполнение самого рандома.
Ответ 6
Нет причин, по которым несколько потоков не могут использовать один и тот же Random. Однако, поскольку класс не является явно потокобезопасным и поддерживает последовательность псевдослучайных чисел через семя. Несколько потоков могут иметь одинаковое случайное число. Было бы лучше создать несколько Randoms для каждого потока и разделить их по-разному.
РЕДАКТИРОВАТЬ. Я только заметил, что реализация Sun использует AtomicLong, поэтому я думаю, что это потокобезопасно (как также отметил Питер Лоури (+1)).
EDIT2: OpenJDK также использует AtomicLong для семени. Как говорили другие, хотя и нехорошо полагаться на это.
Ответ 7
Вот как я столкнулся с проблемой, не предполагая, что 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());
}
};
Ответ 8
Класс Random
не настроен для того, чтобы один экземпляр использовался в нескольких потоках. Конечно, если вы это сделали, вероятно, вы увеличите вероятность непредсказуемости и приближения к случайным числам. Но так как это псевдослучайный генератор, я не понимаю, почему вам нужно разделить экземпляр. Существует ли более конкретное требование?