Update ThreadLocalRandom benchmark to show issues with contention (#8292)

Previous benchmark was measuring initialization of thread pools and
their shutdown, not really measuring performance of Random.nextInt()
shared Random instance vs ThreadLocalRandom.current()

Example when run with 8 threads

Benchmark                                                         Mode  Cnt     Score     Error   Units
ThreadLocalRandomBenchMarker.randomValuesUsingRandom             thrpt   20     9.597 ±   0.475  ops/us
ThreadLocalRandomBenchMarker.randomValuesUsingThreadLocalRandom  thrpt   20  2195.178 ± 109.579  ops/us
This commit is contained in:
karl82 2020-01-30 20:10:20 +01:00 committed by GitHub
parent edc39bfffd
commit 0b73db930f
2 changed files with 21 additions and 46 deletions

View File

@ -1,22 +1,27 @@
package com.baeldung.threadlocalrandom; package com.baeldung.threadlocalrandom;
import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.ChainedOptionsBuilder;
import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.OptionsBuilder;
import com.google.common.collect.ImmutableList;
public class ThreadLocalRandomBenchMarkRunner { public class ThreadLocalRandomBenchMarkRunner {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
Options options = new OptionsBuilder().include(ThreadLocalRandomBenchMarker.class.getSimpleName()) ChainedOptionsBuilder options = new OptionsBuilder().include(ThreadLocalRandomBenchMarker.class.getSimpleName())
.threads(1)
.forks(1) .forks(1)
.shouldFailOnError(true) .shouldFailOnError(true)
.shouldDoGC(true) .shouldDoGC(true)
.jvmArgs("-server") .jvmArgs("-server");
.build();
new Runner(options).run();
for (Integer i : ImmutableList.of(1, 2, 8, 32)) {
new Runner(
options
.threads(i)
.build())
.run();
}
} }
} }

View File

@ -1,64 +1,34 @@
package com.baeldung.threadlocalrandom; package com.baeldung.threadlocalrandom;
import java.util.ArrayList;
import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.annotations.Warmup;
@BenchmarkMode(Mode.AverageTime) @BenchmarkMode(Mode.Throughput)
@Warmup(iterations = 1) @Warmup(iterations = 1)
@OutputTimeUnit(TimeUnit.MICROSECONDS) @OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Benchmark) @State(Scope.Benchmark)
public class ThreadLocalRandomBenchMarker { public class ThreadLocalRandomBenchMarker {
private final Random random = new Random();
List<Callable<Integer>> randomCallables = new ArrayList<>(); @Benchmark
List<Callable<Integer>> threadLocalRandomCallables = new ArrayList<>(); public int randomValuesUsingRandom() {
@Setup(Level.Iteration)
public void init() {
Random random = new Random();
randomCallables = new ArrayList<>();
threadLocalRandomCallables = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
randomCallables.add(() -> {
return random.nextInt(); return random.nextInt();
});
} }
for (int i = 0; i < 1000; i++) { @Benchmark
threadLocalRandomCallables.add(() -> { public int randomValuesUsingThreadLocalRandom() {
return ThreadLocalRandom.current() return ThreadLocalRandom
.current()
.nextInt(); .nextInt();
});
}
}
@Benchmark
public void randomValuesUsingRandom() throws InterruptedException {
ExecutorService executor = Executors.newWorkStealingPool();
executor.invokeAll(randomCallables);
executor.shutdown();
}
@Benchmark
public void randomValuesUsingThreadLocalRandom() throws InterruptedException {
ExecutorService executor = Executors.newWorkStealingPool();
executor.invokeAll(threadLocalRandomCallables);
executor.shutdown();
} }
} }