Java пронизывал Random.nextLong (), возвращая тот же номер - PullRequest
4 голосов
/ 25 января 2011

Я использую библиотеку OAuth, которая вызывает new Random (). NextLong () для генерации одноразовых номеров, однако она генерирует тот же одноразовый номер при асинхронных вызовах. Я сузил его до многопоточности Random.nextLong (), чтобы время от времени возвращать одно и то же точное число.

Кто-нибудь знает, является ли это известным ограничением Java? Если да, кто-нибудь знает о поточно-безопасной работе?

РЕДАКТИРОВАТЬ: я использую Java 1.6

РЕДАКТИРОВАТЬ: Это небольшая программа, которую я сделал, чтобы проверить, что происходит в моем более крупном приложении. Я запускал это несколько раз и чаще, чем следовало, это было одно и то же случайное число, когда время было одинаковым. Пожалуйста, извините за мое быстрое программирование.

public class ThreadedRandom {

/**
 * @param args
 */
public static void main(String[] args) {
    // TODO Auto-generated method stub

    new ThreadedRandom().run();
}

private RandomNumberGenerator _generator;

public ThreadedRandom()
{
    _generator = new RandomNumberGenerator();
}

public void run()
{
    Runnable r = new Runnable() {
        @Override public void run() {
            System.out.println(System.currentTimeMillis()+"\t"+_generator.gen());
        }
    };

    Thread t1, t2;

    t1 = new Thread(r);
    t2 = new Thread(r);

    t1.start();
    t2.start();
}

private class RandomNumberGenerator {

    Random random;
    public RandomNumberGenerator()
    {
        random = new Random();
    }

    public Long gen() {
        return new Random().nextLong();
    }
}

}

Ответы [ 5 ]

4 голосов
/ 25 января 2011

Возможно, вы не захотите каждый раз создавать новый экземпляр Random. Скорее есть глобальный.

2 голосов
/ 25 января 2011

Случайные числа не являются действительно случайными, они являются «псевдослучайными», и для них требуется «начальное» значение.Если используется то же начальное число, будет сгенерирована та же последовательность псевдослучайных значений.

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

http://download.oracle.com/javase/1.4.2/docs/api/java/util/Random.html#Random%28%29

Если вы создаете случайные объекты в течение одной миллисекунды, они будут иметь одинаковую последовательность значений.

Обычно вы хотите разделить один объект Random среди всех потоков, чтобы избежать такого рода проблем.

1 голос
/ 26 января 2011

Вы действительно должны использовать SecureRandom, поскольку вы используете это для чего-то связанного с безопасностью.

1 голос
/ 25 января 2011

Хотя я не сразу знаком с базовой реализацией Random, если бы мне пришлось угадывать, я бы предположил, что вызов new Random() делегатов для new Random(System.currentTimeMillis()). Это дает достаточно разную последовательность Random для Randoms, созданных в разное время.

Однако, поскольку вы упомянули асинхронные вызовы, возможно, ваши вызовы выполняются по существу в одно и то же время. Это означает, что когда потоки вызывают библиотеку, они одновременно выполняют вызов new Random(), и рандомы получают идентичные начальные числа, поэтому они генерируют одинаковую случайную последовательность.

0 голосов
/ 25 января 2011

Я думал, что Рандом не был потокобезопасным, но это так.Вы должны получать Random только с одним и тем же числом каждые 2 ^ 48 значений.

Как уже отмечалось, в Java 1.4 и предыдущих версиях была ошибка, из-за которой два Randoms могли получить одинаковое начальное число.Я предлагаю вам использовать Java 6 или установить начальное значение уникальным самостоятельно.

Следует также отметить, что Random использует 48-разрядное начальное число.Это означает, что он будет повторяться после 2 ^ 48 значений и будет давать только 2 ^ 48 уникальных длинных значений.Если это проблема для вас, используйте SecureRandom, который намного дороже, но выдаст все возможные длинные значения.

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