Является ли случайный класс потоком безопасным?

Можно ли использовать один экземпляр класса Random между несколькими потоками? И вызвать nextInt(int) из нескольких потоков в частности?

Ответы

Ответ 1

Он потокобезопасен в том смысле, что он будет генерировать случайные числа при использовании несколькими потоками.

Реализация JVM Sun/Oracle использует синхронизированные и AtomicLong в качестве семян для улучшения согласованности потоков. Но, похоже, он не защищен на всех платформах документации.

Я бы не написал вашу программу, чтобы требовать такую ​​гарантию, тем более, что вы не можете определить порядок, в котором будет вызываться nextInt().

Ответ 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 не настроен для того, чтобы один экземпляр использовался в нескольких потоках. Конечно, если вы это сделали, вероятно, вы увеличите вероятность непредсказуемости и приближения к случайным числам. Но так как это псевдослучайный генератор, я не понимаю, почему вам нужно разделить экземпляр. Существует ли более конкретное требование?