Use of threadlocalrandom in Java
Use of threadlocalrandom in Java
In Java, we usually need to use Java util. Random to facilitate the production of random numbers. However, random is thread safe. If it is used in a threaded environment, it may cause performance bottlenecks.
Let's take the nextint method commonly used in random as an example:
public int nextInt() {
return next(32);
}
The nextint method actually calls the following method:
protected int next(int bits) {
long oldseed, nextseed;
AtomicLong seed = this.seed;
do {
oldseed = seed.get();
nextseed = (oldseed * multiplier + addend) & mask;
} while (!seed.compareAndSet(oldseed, nextseed));
return (int)(nextseed >>> (48 - bits));
}
From the code, we can see that atomiclong is used inside the method and its compareandset method is called to ensure thread safety. So this is a thread safe method.
In fact, in a multi-threaded environment, random simply needs to share instances. What should I do?
A threadlocalrandom class is introduced in JDK 7. As we all know, ThreadLocal is the local variable of the thread, and threadlocalrandom is the local random of the thread.
Let's see how to call:
ThreadLocalRandom.current().nextInt();
Let's write a benchmark test for these two classes:
public class RandomUsage {
public void testRandom() throws InterruptedException {
ExecutorService executorService=Executors.newFixedThreadPool(2);
Random random = new Random();
List<Callable<Integer>> callables = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
callables.add(() -> {
return random.nextInt();
});
}
executorService.invokeAll(callables);
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(RandomUsage.class.getSimpleName())
// 预热5轮
.warmupIterations(5)
// 度量10轮
.measurementIterations(10)
.forks(1)
.build();
new Runner(opt).run();
}
}
public class ThreadLocalRandomUsage {
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public void testThreadLocalRandom() throws InterruptedException {
ExecutorService executorService=Executors.newFixedThreadPool(2);
List<Callable<Integer>> callables = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
callables.add(() -> {
return ThreadLocalRandom.current().nextInt();
});
}
executorService.invokeAll(callables);
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(ThreadLocalRandomUsage.class.getSimpleName())
// 预热5轮
.warmupIterations(5)
// 度量10轮
.measurementIterations(10)
.forks(1)
.build();
new Runner(opt).run();
}
}
By analyzing the running results, we can see that threadlocalrandom is faster than random in a multithreaded environment.
Examples of this article can be referred to https://github.com/ddean2009/learn-java-concurrency/tree/master/ThreadLocalRandom
For updated articles, please refer to flydean's blog