Чи безпечна нитка класів?


110

Чи справедливо ділити один екземпляр Randomкласу між декількома потоками? І зокрема зателефонувати nextInt(int)з декількох потоків?


@Bala R, ні, ми говоримо не про випадковий об'єкт C #, а про Java.
Buhake Sindi

ой. вибачте пропустив цю частину
Бала R

Обережно використання випадкових даних для отримання чисел у багатопотоковому середовищі може дати вам погані результати. Можливо, це не має значення, але якщо ви робите деякі симуляції, це добре знати.
Maxence SCHMITT

14
Для подальших читачів: є новий клас з 1,7 іменем java.util.concurrent.ThreadLocalRandom.
Джин Квон

Відповіді:


66

Це безпечно для потоків, в тому сенсі, що він все одно генерує випадкові числа при використанні кількох потоків.

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

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


69
Документи Java 7 додано гарантію: "Екземпляри java.util.Random є безпечними нитками." docs.oracle.com/javase/7/docs/api/java/util/Random.html
Matt R


8

Згідно з документацією, Math.random () гарантує, що вона безпечна для використання в декількох потоках . Але клас Random цього не робить. Я б припустив, що тоді вам доведеться синхронізувати це самостійно.


7

Так, Random є безпечним для потоків. nextInt()метод викликає захищений next(int)метод , який використовує AtomicLong seed, nextseed(атомний довгий) для створення наступного насіння. AtomicLongзастосовується для безпеки ниток при генерації насіння.


6

Як було сказано, це збереження ниток, але це може бути розумно використовувати java.util.concurrent.ThreadLocalRandomвідповідно до цієї статті (посилання мертве). ThreadLocalRandom також є підкласом Random, тому він сумісний ззаду назад.

У статті пов'язані між собою порівнюваних результати різних класів випадкових профілювання: java.util.Random, java.util.concurrent.ThreadLocalRandom і java.lang.ThreadLocal<java.util.Random>. Результати показали, що використання ThreadLocalRandom є найбільш ефективним, за ним слідує ThreadLocal та найгірше виконання Random.


4

Немає причини, що кілька потоків не можуть використовувати один і той же Random. Однак, оскільки клас явно не є безпечним для потоків і підтримує послідовність псевдовипадкових чисел через насіння. Кілька ниток можуть закінчуватися одним і тим же випадковим числом. Було б краще створити декілька Randoms для кожної нитки та посіяти їх по-різному.

EDIT : Я щойно помітив, що впровадження Sun використовує AtomicLong, тому я гадаю, що це безпечно для потоків (як також зазначив Пітер Лоурі (+1)).

EDIT2 : OpenJDK також використовує AtomicLong для насіння. Як казали інші, хоча на це все ще недобре покладатися.


3

Ось як я вирішив проблему, не припускаючи, що 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)значна частина?
Джин Квон

1
Так, це було брудним виправленням. (24*60*60*1000)Було так , що потік з ідентифікатором 12вxxxxxxxxxx045 Millis не отримав висівають таким же , як нитка 22в xxxxxxxxxx035Millis. Однак я не маю жодних вагомих причин вважати, що ідентифікатори потоків наростають, і немає жодної вагомої причини думати, що я створюю теми в більш випадкові часи завтра, ніж сьогодні. Я спростив alg зараз і оновив опис, щоб визначити недолік.
Райан

0

RandomКлас не налаштований для одного примірника , які будуть використовуватися в декількох потоках. Звичайно, якщо ви зробили це, швидше за все, ви збільшите можливість отримати непередбачувані та наблизитись до випадкових чисел. Але оскільки це псевдовипадковий генератор, я не можу зрозуміти, чому вам потрібно поділитися екземпляром. Чи є більш конкретна вимога?

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.