From 8bf612c07a74b0650368386c9ed35eb5cd881b9f Mon Sep 17 00:00:00 2001 From: Daniel Strmecki Date: Thu, 6 Jan 2022 09:54:44 +0100 Subject: [PATCH] Feature/bael 5176 random number generators (#11641) * BAEL-5176: Add simple test * BAEL-5176: Add benchmark runner * BAEL-5176: Update examples * BAEL-5176: Refactor * BAEL-5176: Refactor * BAEL-5176: Refactor --- core-java-modules/core-java-17/pom.xml | 21 ++++ .../randomgenerators/BenchmarkRunner.java | 115 ++++++++++++++++++ .../randomgenerators/GeneratorFactory.java | 36 ++++++ .../baeldung/randomgenerators/OldRandom.java | 12 ++ .../SplittableGeneratorMultiThread.java | 30 +++++ .../src/main/java/module-info.java | 3 + .../GeneratorFactoryUnitTest.java | 21 ++++ .../GeneratorSelectionUnitTest.java | 25 ++++ .../randomgenerators/OldRandomUnitTest.java | 15 +++ ...plittableGeneratorMultiThreadUnitTest.java | 17 +++ 10 files changed, 295 insertions(+) create mode 100644 core-java-modules/core-java-17/src/main/java/com/baeldung/randomgenerators/BenchmarkRunner.java create mode 100644 core-java-modules/core-java-17/src/main/java/com/baeldung/randomgenerators/GeneratorFactory.java create mode 100644 core-java-modules/core-java-17/src/main/java/com/baeldung/randomgenerators/OldRandom.java create mode 100644 core-java-modules/core-java-17/src/main/java/com/baeldung/randomgenerators/SplittableGeneratorMultiThread.java create mode 100644 core-java-modules/core-java-17/src/test/java/com/baeldung/randomgenerators/GeneratorFactoryUnitTest.java create mode 100644 core-java-modules/core-java-17/src/test/java/com/baeldung/randomgenerators/GeneratorSelectionUnitTest.java create mode 100644 core-java-modules/core-java-17/src/test/java/com/baeldung/randomgenerators/OldRandomUnitTest.java create mode 100644 core-java-modules/core-java-17/src/test/java/com/baeldung/randomgenerators/SplittableGeneratorMultiThreadUnitTest.java diff --git a/core-java-modules/core-java-17/pom.xml b/core-java-modules/core-java-17/pom.xml index 2fe16cad57..bc949d9050 100644 --- a/core-java-modules/core-java-17/pom.xml +++ b/core-java-modules/core-java-17/pom.xml @@ -27,6 +27,13 @@ --enable-preview ${maven.compiler.source.version} ${maven.compiler.target.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh-generator.version} + + @@ -49,6 +56,20 @@ + + + org.openjdk.jmh + jmh-core + ${jmh-core.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh-generator.version} + test + + + 17 17 diff --git a/core-java-modules/core-java-17/src/main/java/com/baeldung/randomgenerators/BenchmarkRunner.java b/core-java-modules/core-java-17/src/main/java/com/baeldung/randomgenerators/BenchmarkRunner.java new file mode 100644 index 0000000000..9a40a2de4e --- /dev/null +++ b/core-java-modules/core-java-17/src/main/java/com/baeldung/randomgenerators/BenchmarkRunner.java @@ -0,0 +1,115 @@ +package com.baeldung.randomgenerators; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; + +import java.util.concurrent.TimeUnit; +import java.util.random.RandomGenerator; + +public class BenchmarkRunner { + + public static void main(String[] args) throws Exception { + org.openjdk.jmh.Main.main(args); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void testL128X1024MixRandom() { + generateRandomNumbers(RandomGenerator.of("L128X1024MixRandom")); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void testL128X128MixRandom() { + generateRandomNumbers(RandomGenerator.of("L128X128MixRandom")); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void testL128X256MixRandom() { + generateRandomNumbers(RandomGenerator.of("L128X256MixRandom")); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void testL32X64MixRandom() { + generateRandomNumbers(RandomGenerator.of("L32X64MixRandom")); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void testL64X1024MixRandom() { + generateRandomNumbers(RandomGenerator.of("L64X1024MixRandom")); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void testL64X128MixRandom() { + generateRandomNumbers(RandomGenerator.of("L64X128MixRandom")); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void testL64X128StarStarRandom() { + generateRandomNumbers(RandomGenerator.of("L64X128StarStarRandom")); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void testL64X256MixRandom() { + generateRandomNumbers(RandomGenerator.of("L64X256MixRandom")); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void testRandom() { + generateRandomNumbers(RandomGenerator.of("Random")); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void testSecureRandom() { + generateRandomNumbers(RandomGenerator.of("SecureRandom")); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void testSplittableRandom() { + generateRandomNumbers(RandomGenerator.of("SplittableRandom")); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void testXoroshiro128PlusPlus() { + generateRandomNumbers(RandomGenerator.of("Xoroshiro128PlusPlus")); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public static void testXoshiro256PlusPlus() { + generateRandomNumbers(RandomGenerator.of("Xoshiro256PlusPlus")); + } + + private static void generateRandomNumbers(RandomGenerator generator) { + generator.nextLong(); + generator.nextInt(); + generator.nextFloat(); + generator.nextDouble(); + } + +} diff --git a/core-java-modules/core-java-17/src/main/java/com/baeldung/randomgenerators/GeneratorFactory.java b/core-java-modules/core-java-17/src/main/java/com/baeldung/randomgenerators/GeneratorFactory.java new file mode 100644 index 0000000000..64bc81a035 --- /dev/null +++ b/core-java-modules/core-java-17/src/main/java/com/baeldung/randomgenerators/GeneratorFactory.java @@ -0,0 +1,36 @@ +package com.baeldung.randomgenerators; + +import java.util.Comparator; +import java.util.random.RandomGenerator; +import java.util.random.RandomGeneratorFactory; + +public class GeneratorFactory { + + public static void main(String[] args) { + System.out.println("Group\tName\tJumpable?\tSplittable?"); + RandomGeneratorFactory.all() + .sorted(Comparator.comparing(RandomGeneratorFactory::name)) + .forEach(factory -> System.out.println(String.format("%s\t%s\t%s\t%s", + factory.group(), + factory.name(), + factory.isJumpable(), + factory.isSplittable()))); + } + + public static int getRandomInt(RandomGenerator generator, int bound) { + return generator.nextInt(bound); + } + + public static RandomGenerator getDefaultGenerator() { + return RandomGeneratorFactory.getDefault().create(); + } + + public static RandomGenerator getJumpableGenerator() { + return RandomGeneratorFactory.all() + .filter(RandomGeneratorFactory::isJumpable) + .findAny() + .map(RandomGeneratorFactory::create) + .orElseThrow(() -> new RuntimeException("Error creating a generator")); + } + +} diff --git a/core-java-modules/core-java-17/src/main/java/com/baeldung/randomgenerators/OldRandom.java b/core-java-modules/core-java-17/src/main/java/com/baeldung/randomgenerators/OldRandom.java new file mode 100644 index 0000000000..c84d5bc8d3 --- /dev/null +++ b/core-java-modules/core-java-17/src/main/java/com/baeldung/randomgenerators/OldRandom.java @@ -0,0 +1,12 @@ +package com.baeldung.randomgenerators; + +import java.util.Random; + +public class OldRandom { + + public static int getRandomInt(int bound) { + Random random = new Random(); + return random.nextInt(bound); + } + +} diff --git a/core-java-modules/core-java-17/src/main/java/com/baeldung/randomgenerators/SplittableGeneratorMultiThread.java b/core-java-modules/core-java-17/src/main/java/com/baeldung/randomgenerators/SplittableGeneratorMultiThread.java new file mode 100644 index 0000000000..298d840da9 --- /dev/null +++ b/core-java-modules/core-java-17/src/main/java/com/baeldung/randomgenerators/SplittableGeneratorMultiThread.java @@ -0,0 +1,30 @@ +package com.baeldung.randomgenerators; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.random.RandomGenerator; +import java.util.random.RandomGeneratorFactory; + +public class SplittableGeneratorMultiThread { + + public static List generateNumbersInMultipleThreads() { + List numbers = Collections.synchronizedList(new ArrayList<>()); + ExecutorService executorService = Executors.newCachedThreadPool(); + + RandomGenerator.SplittableGenerator sourceGenerator = RandomGeneratorFactory + .of("L128X256MixRandom") + .create(); + + sourceGenerator.splits(20).forEach((splitGenerator) -> { + executorService.submit(() -> { + numbers.add(splitGenerator.nextInt(10)); + }); + }); + + return numbers; + } + +} diff --git a/core-java-modules/core-java-17/src/main/java/module-info.java b/core-java-modules/core-java-17/src/main/java/module-info.java index b1ce62aa68..319678832e 100644 --- a/core-java-modules/core-java-17/src/main/java/module-info.java +++ b/core-java-modules/core-java-17/src/main/java/module-info.java @@ -1,4 +1,7 @@ module core.java { requires jdk.incubator.vector; requires jdk.incubator.foreign; + requires jmh.core; + requires jdk.unsupported; + exports com.baeldung.randomgenerators.jmh_generated; } \ No newline at end of file diff --git a/core-java-modules/core-java-17/src/test/java/com/baeldung/randomgenerators/GeneratorFactoryUnitTest.java b/core-java-modules/core-java-17/src/test/java/com/baeldung/randomgenerators/GeneratorFactoryUnitTest.java new file mode 100644 index 0000000000..b009b4eeb0 --- /dev/null +++ b/core-java-modules/core-java-17/src/test/java/com/baeldung/randomgenerators/GeneratorFactoryUnitTest.java @@ -0,0 +1,21 @@ +package com.baeldung.randomgenerators; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class GeneratorFactoryUnitTest { + + @Test + void givenDefaultGenerator_whenGeneratingAnInt_thenIntInRangeIsGenerated() { + int number = GeneratorFactory.getRandomInt(GeneratorFactory.getDefaultGenerator(), 10); + assertThat(number).isNotNegative().isLessThan(10); + } + + @Test + void givenJumpableGenerator_whenGeneratingAnInt_thenIntInRangeIsGenerated() { + int number = GeneratorFactory.getRandomInt(GeneratorFactory.getJumpableGenerator(), 10); + assertThat(number).isNotNegative().isLessThan(10); + } + +} diff --git a/core-java-modules/core-java-17/src/test/java/com/baeldung/randomgenerators/GeneratorSelectionUnitTest.java b/core-java-modules/core-java-17/src/test/java/com/baeldung/randomgenerators/GeneratorSelectionUnitTest.java new file mode 100644 index 0000000000..0732c3f54e --- /dev/null +++ b/core-java-modules/core-java-17/src/test/java/com/baeldung/randomgenerators/GeneratorSelectionUnitTest.java @@ -0,0 +1,25 @@ +package com.baeldung.randomgenerators; + +import org.junit.jupiter.api.Test; + +import java.util.random.RandomGenerator; + +import static org.assertj.core.api.Assertions.assertThat; + +class GeneratorSelectionUnitTest { + + @Test + void givenDefaultGenerator_whenGeneratingAnInt_thenIntInRangeIsGenerated() { + RandomGenerator generator = RandomGenerator.getDefault(); + int number = generator.nextInt(10); + assertThat(number).isNotNegative().isLessThan(10); + } + + @Test + void givenSpecificGenerator_whenGeneratingAnInt_thenIntInRangeIsGenerated() { + RandomGenerator generator = RandomGenerator.of("L128X256MixRandom"); + int number = generator.nextInt(10); + assertThat(number).isNotNegative().isLessThan(10); + } + +} diff --git a/core-java-modules/core-java-17/src/test/java/com/baeldung/randomgenerators/OldRandomUnitTest.java b/core-java-modules/core-java-17/src/test/java/com/baeldung/randomgenerators/OldRandomUnitTest.java new file mode 100644 index 0000000000..4a18369686 --- /dev/null +++ b/core-java-modules/core-java-17/src/test/java/com/baeldung/randomgenerators/OldRandomUnitTest.java @@ -0,0 +1,15 @@ +package com.baeldung.randomgenerators; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class OldRandomUnitTest { + + @Test + void givenOldRandomApi_whenGeneratingAnInt_thenIntInRangeIsGenerated() { + int number = OldRandom.getRandomInt(10); + assertThat(number).isNotNegative().isLessThan(10); + } + +} diff --git a/core-java-modules/core-java-17/src/test/java/com/baeldung/randomgenerators/SplittableGeneratorMultiThreadUnitTest.java b/core-java-modules/core-java-17/src/test/java/com/baeldung/randomgenerators/SplittableGeneratorMultiThreadUnitTest.java new file mode 100644 index 0000000000..ba4cd8eb2b --- /dev/null +++ b/core-java-modules/core-java-17/src/test/java/com/baeldung/randomgenerators/SplittableGeneratorMultiThreadUnitTest.java @@ -0,0 +1,17 @@ +package com.baeldung.randomgenerators; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class SplittableGeneratorMultiThreadUnitTest { + + @Test + void givenSplittableGenerator_whenUsingMultipleThreads_thenListOfIntsIsGenerated() { + List numbers = SplittableGeneratorMultiThread.generateNumbersInMultipleThreads(); + assertThat(numbers).hasSize(20).allMatch(number -> number >= 0 && number <= 10); + } + +}