ИМХО сомневаюсь, что вы не случайные числа генерируете

Java

Однажды, когда я просматривал Stack Overflow, я нашел такой вопрос: «Как сгенерировать случайное число в пределах указанного диапазона в Java», я подумал: «Это сломанный вопрос, на самом деле 3,98 миллиона просмотров, статистика Вы уверен, что ты прав? Только одинMath.random()Это что-то. "

Поэтому я напрямую использовал свою власть, чтобы проголосовать против этого. В итоге, перед тем как дождаться радости после реализации силы, я получил напоминание: "Люди со значением репутации ниже 125 имеют право голоса, но они не будут отображаться публично". Просто бросайтесь на меня и доказывайте свою силу без кода.У меня еще есть лицо, чтобы сказать, что у меня есть десятилетний опыт разработки? Поэтому я взволнованно открыл IDEA и набрал следующий код:

public class GenerateMathRandomInteger {
    public static void main(String[] args) {
        int leftLimit = 2;
        int rightLimit = 11;

        Runnable r = () -> {
            int generatedInteger = leftLimit + (int) (Math.random() * rightLimit);
            System.out.println(generatedInteger);
        };
       for (int i = 1; i < 10; i++) {
           new Thread(r).start();
       }
    }
}

Я правильно написал этот код, верно? На первый взгляд имена параметров и классов кажутся разумными, и даже используются лямбда-выражения. Но вывод программы превзошел все мои ожидания:

8
10
10
4
3
4
6
12
3

Откуда взялось 12? Конечно, это произошло из-за ошибки в программе.leftLimit + (int) (Math.random() * rightLimit)Сгенерированное случайное число может быть за пределами указанного диапазона. нет,Math.random()Хотите верьте, хотите нет, но должен быть другой подход. По прихоти я подумалRandomclass, поэтому я написал новый код:

public class GenerateRandomInteger {
    public static void main(String[] args) {
        int leftLimit = 2;
        int rightLimit = 11;

        Random random = new Random();
        int range = rightLimit - leftLimit + 1;

        Runnable r = () -> {
            int generatedInteger = leftLimit + random.nextInt() % range;
            System.out.println(generatedInteger);
        };
       for (int i = 1; i < 10; i++) {
           new Thread(r).start();
       }
    }
}

На этот раз, я уверен,Math.random()неразрешимые проблемы,random.nextInt()должны быть решены. В итоге выход снова влепил мне пощечину.

0
-3
10
2
2
-4
-4
-6
6

Есть еще отрицательные числа. Это действительно жестокая реальность. Я получил образование, и, кажется, ко мне вернулось ощущение, что меня будут разорять лидеры, когда я впервые присоединился к компании. К счастью, мой менталитет уже не такой раздражительный, как в молодости, и я стабилен: неважно, есть ли проблема, в самый раз нужно найти решение.

Итак, через 5 минут я написал следующий код:

public class GenerateRandomInteger {
    public static void main(String[] args) {
        int leftLimit = 2;
        int rightLimit = 11;

        Random random = new Random();
        int range = rightLimit - leftLimit;

        Runnable r = () -> {
            int generatedInteger = leftLimit + (int)(random.nextFloat() * range);
            System.out.println(generatedInteger);
        };
       for (int i = 1; i < 10; i++) {
           new Thread(r).start();
       }
    }
}

Будь то корректировка количества потоков или повторный запуск несколько раз, результаты будут такими, как и ожидалось, от 2 до 11.

7
2
5
8
6
2
9
9
7

nextFloat()Метод возвращает случайное число с плавающей запятой, равномерно распределенное между 0 и 1 (включая 0,0f, но не 1,0f), умноженное на разницу между максимальным значением и минимальным значением, а затем приводится к типу int, чтобы гарантировать, что случайное число находится между 0 и (максимум-минимум), и, наконец, добавьте минимальное значение, вы можете просто получить числа в указанном диапазоне.

Если вы хотите прочитать исходный код, вы обнаружите, что класс Random имеетnextInt(int bound)метод, который возвращает случайное целое число, равномерно распределенное между 0 и границей (включая 0, но не включая указанную границу). Затем вы также можете использовать этот метод для получения допустимого случайного числа, см. пример кода.

public class GenerateRandomNextInt {
    public static void main(String[] args) {
        int leftLimit = 2;
        int rightLimit = 11;

        Random random = new Random();
        Runnable r = () -> {
            int generatedInteger = leftLimit + random.nextInt(rightLimit - leftLimit + 1);
            System.out.println(generatedInteger);
        };
       for (int i = 1; i < 10; i++) {
           new Thread(r).start();
       }
    }
}

так какnextInt()Не содержит границ, поэтому требуется +1. Результат работы программы также ожидаем:

8
2
9
8
4
6
4
5
7

Видите ли, мои предыдущие две попытки не увенчались успехом, но я все же не терял надежды и после собственных размышлений нашел еще два возможных решения. Это напоминает мне одно из стихотворений Пушкина:

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

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

public class GenerateRandomThreadLocal {
    public static void main(String[] args) {
        int leftLimit = 2;
        int rightLimit = 11;

        Runnable r = () -> {
            int generatedInteger = ThreadLocalRandom.current().nextInt(leftLimit, rightLimit +1);
            System.out.println(generatedInteger);
        };
       for (int i = 1; i < 10; i++) {
           new Thread(r).start();
       }
    }
}

Вывод программы следующий:

11
9
6
10
6
6
10
7
3

Класс ThreadLocalRandom наследуется от класса Random, который инициализируется внутренне сгенерированным начальным числом (которое нельзя установить извне, поэтому тестовый сценарий нельзя воспроизвести), и ему не нужно явно использовать ключевое слово new для создания объекта (Random может быть заполненным конструктором), вы можете напрямую передать статический методcurrent()Получить объект для локального уровня потока:

static final ThreadLocalRandom instance = new ThreadLocalRandom();

static final void localInit() {
    int p = probeGenerator.addAndGet(PROBE_INCREMENT);
    int probe = (p == 0) ? 1 : p; // skip 0
    long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
    Thread t = Thread.currentThread();
    U.putLong(t, SEED, seed);
    U.putInt(t, PROBE, probe);
}

public static ThreadLocalRandom current() {
    if (U.getInt(Thread.currentThread(), PROBE) == 0)
        localInit();
    return instance;
}

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

Наконец, я предлагаю еще одно решение, использующее класс RandomDataGenerator из библиотеки Apache Commons Math. Перед использованием библиотеки классов необходимо ввести зависимость библиотеки классов в файле pom.xml.

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-math3</artifactId>
    <version>3.6.1</version>
</dependency>

Когда вам нужно генерировать случайные числа в указанном диапазоне, используйтеnew RandomDataGenerator()Получите экземпляр случайного генератора, затем используйтеnextInt()Метод напрямую получает случайное число между максимальным и минимальным значениями. См. пример.

public class RandomDataGeneratorDemo {
    public static void main(String[] args) {
        int leftLimit = 2;
        int rightLimit = 11;

        Runnable r = () -> {
            int generatedInteger = new RandomDataGenerator().nextInt( leftLimit,rightLimit);
            System.out.println(generatedInteger);
        };
       for (int i = 1; i < 10; i++) {
           new Thread(r).start();
       }
    }
}

Результат выглядит следующим образом:

8
4
4
4
10
3
10
3
6

Вышло именно так, как мы и ожидали - это было также мое последнее средство, и я был так счастлив дать вам все это.

Что ж, мои дорогие читатели, на этом все. Если вы считаете, что статья полезна для вас, пожалуйста, выполните поиск по запросу "Тихий король 2"Читал в первый раз. Пример кода был загружен на GitHub,Портал~

Я Silent King Er, интересный программист.Оригинальность не так проста, не просите пустой билет, пожалуйста, поставьте лайк этой статье, это будет сильнейшей мотивацией для меня писать больше качественных статей.