Поток класса Random безопасен? - PullRequest
101 голосов
/ 28 апреля 2011

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

Ответы [ 8 ]

62 голосов
/ 28 апреля 2011

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

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

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

23 голосов
/ 28 апреля 2011

Это потокобезопасно, хотя это было не всегда.

Подробнее см. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6362070.

8 голосов
/ 28 апреля 2011

Согласно документации, Math.random () гарантирует безопасность использования несколькими потоками. Но случайный класс не делает. Полагаю, тогда вам придется синхронизировать это самостоятельно.

7 голосов
/ 28 апреля 2011

Да, Random это потокобезопасный. метод nextInt() вызывает защищенный метод next(int), который использует AtomicLong seed, nextseed (длина атома) для генерации следующего начального числа. AtomicLong используется для обеспечения безопасности нитей при генерации семян.

5 голосов
/ 26 мая 2017

Как уже говорилось, это сохранение потока, но может быть разумно использовать java.util.concurrent.ThreadLocalRandom в соответствии с этой статьей (ссылка недействительна). ThreadLocalRandom также является подклассом Random, поэтому он обратно совместим.

Статья связала сопоставленные результаты профилирования различных Random классы: java.util.Random, java.util.concurrent.ThreadLocalRandom и java.lang.ThreadLocal<java.util.Random>. Результаты показали, что использование ThreadLocalRandom наиболее эффективно, а затем ThreadLocal и худший из всех рандомов.

4 голосов
/ 28 апреля 2011

Нет причин, по которым все потоки не могут использовать один и тот же Random. Однако, поскольку класс не является явно поточно-ориентированным и поддерживает последовательность псевдослучайных чисел через начальное число. Несколько потоков могут заканчиваться одним и тем же случайным числом. Было бы лучше создать несколько рандомов для каждого потока и посеять их по-разному.

РЕДАКТИРОВАТЬ : Я только что заметил, что реализация Sun использует AtomicLong, так что я думаю, что она поточно-ориентирована (как также отметил Питер Лори (+1)).

EDIT2 : OpenJDK также использует AtomicLong для начального числа. Как уже говорили другие, полагаться на это все же нехорошо.

3 голосов
/ 02 октября 2011

Вот как я справился с проблемой, не предполагая, что 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());
    }
};
0 голосов
/ 28 апреля 2011

Класс Random не настроен для одного экземпляра, который будет использоваться в нескольких потоках. Конечно, если вы сделали это, скорее всего, вы увеличите вероятность стать непредсказуемым и приблизиться к случайным числам. Но так как это псевдослучайный генератор, я не понимаю, зачем вам нужно делиться экземпляром. Есть ли более конкретное требование?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...