Hello,
I have noticed in Java 25 (and earlier versions) that calling
ThreadLocalRandom.current().nextGaussian() uses the Random.nextGaussian()
implementation, which is synchronized. Under heavy load in a multithreaded
environment, I was detecting lock contention.
Here is a very simple reproducer:
ThreadLocalRandom r = ThreadLocalRandom.current();
// step into this call using a debugger
r.nextGaussian();
It dispatches to the synchronized Random implementation, since
ThreadLocalRandom extends Random, thus the default implementation (not
synchronizing) on RandomGenerator is not used.
Sketch:
public interface RandomGenerator {
default double nextGaussian() {
// remove TAOCP comment since it is out of date
return RandomSupport.computeNextGaussian(this);
}
}
public class Random implements RandomGenerator {
@Override
public synchronized double nextGaussian() {
// synchronized version ...
}
}
public class ThreadLocalRandom extends Random {
// ADD THIS
@Override
public double nextGaussian() {
return RandomSupport.computeNextGaussian(this);
}
}
A comment on ThreadLocalRandom introduced in JDK-8248862 states "This
implementation of ThreadLocalRandom overrides the definition of the
nextGaussian() method in the class Random, and instead uses the ziggurat-based
algorithm that is the default for the RandomGenerator interface.” However,
there is none such override happening. It appears that prior to JDK-8248862 and
a0ec2cb289463969509fe508836e3faf789f46d8 the nextGaussian implementation was
non-locking since it used proper ThreadLocals.
I have a patch which remedies this by using the same implementation as
RandomGenerator. I am willing to submit
https://github.com/openjdk/jdk/compare/master...yuzawa-san:jdk:refs/heads/thread-local-random-nextGaussian
Per the contribution instructions, I have signed the OCA in prior work on
project Panama, but am looking for community input, sponsorship, and help
creating an issue if this is something we wish to pursue.
Thank you,
James Yuzawa