RFR: 8372134: ThreadLocalRandom no longer overrides nextGaussian [v4]

James Yuzawa duke at openjdk.org
Thu Nov 27 13:30:06 UTC 2025


> 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, and this uses the ziggurat algorithm instead
> 		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 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 a0ec2cb289463969509fe508836e3faf789f46d8 the nextGaussian implementation was non-locking since it used proper ThreadLocals.
> 
> I conducted an audit of all of the RandomGenerator and Random methods to see if there are any others:
> 
> 
> Set<String> tlrMethods = new HashSet<>();
> for (Method method : java.util.concurrent.ThreadLocalRandom.class.getDeclaredMethods()) {
> 	int mod = method.getModifiers();
> 	if (!Modifier.isStatic(mod) && Modifier.isPublic(mod)) {
> 		String desc =
> 				method.getReturnType() + " " + method.getName() + " " + Arrays.toString(method.getParameters());
> 		tlrMethods.add(desc);
> 	}
> }
> for (Method method : java.util.Random.class.getDeclaredMethods()) {
> 	int mod = method.getModifiers();
> 	if (!Modifier.isStatic(mod) && Modifier.isPublic(mod)) {
> 		String desc =
> 				method.getReturnType() + " " + method.getName() + " " + Arrays.toString(method.getParameters());
> 		if (!tlrMethods.contains(desc)) {
> 			System.out.println(desc);
> 		}
> 	}
> }
> 
> 
> That prints
> 
> void nextBytes [byte[] arg0]
> double nextGaussian []
> 
> 
> The former safely calls `Thread...

James Yuzawa has updated the pull request incrementally with one additional commit since the last revision:

  8372134: ThreadLocalRandom no longer overrides nextGaussian
  
  Update copyright header

-------------

Changes:
  - all: https://git.openjdk.org/jdk/pull/28483/files
  - new: https://git.openjdk.org/jdk/pull/28483/files/54228b28..57d0d4f7

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk&pr=28483&range=03
 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=28483&range=02-03

  Stats: 1 line in 1 file changed: 0 ins; 0 del; 1 mod
  Patch: https://git.openjdk.org/jdk/pull/28483.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/28483/head:pull/28483

PR: https://git.openjdk.org/jdk/pull/28483


More information about the core-libs-dev mailing list