JDK-8218282 : Use ThreadLocalRandom As Default RNG For Collection Shuffle
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.util:collections
  • Affected Version: 8,11,12,13
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2019-02-01
  • Updated: 2022-10-11
Related Reports
Relates :  
Description
A DESCRIPTION OF THE PROBLEM :
For the default random number generator in Collections.shuffle(), please consider using java.util.concurrent.ThreadLocalRandom instead of the current static copy of Random that is shared across all threads.

Related to: JDK-6271215



Comments
OK to all of the above. Regarding use of TLR, I don't really intend to create a controversy. Rather, when this bug was filed, RandomGenerator didn't exist, and the "obvious" way to get better randomness for `shuffle(List)` was to use TLR. We might want to revisit that, now that we have RandomGenerator and Loom, both of which potentially change the situation.
11-10-2022

> For (2) instead of fiddling around with trying to fix the behavior of this old API, maybe we should just leave it in place, (and possibly even deprecate it) and update the docs to tell people to use RandomGenerator instead. As a JDK user, I would disagree to deprecate this method or discourage its use. Many people don't care much about RNG properties like distribution, autocorrelation, or predictability of result. They want the simplest way to shuffle the collection 'somehow'. Requiring them to think about which RNG to use and how to seed it does not look like a good idea, when we can provide a sensible default. > This might be an issue for virtual threads. Is TLR used so frequently that every virtual thread instance should pay for it? Note that TLR can be used in many different places of code, so payment could be already done elsewhere. Also, we don't document TLR API as "avoid using it as much as possible, as it could be costly". Rather opposite, we recommend it to use in multithreading code. So I don't see why we should not follow our own recommendations: > Use of ThreadLocalRandom is particularly appropriate when multiple tasks (for example, each a ForkJoinTask) use random numbers in parallel in thread pools. By the way, discovered the following spec issue: JDK-8295008.
08-10-2022

Revisiting this since it came up in the context of Collections.shuffle(RandomGenerator). See JDK-8294693, and this discussion thread: https://mail.openjdk.org/pipermail/core-libs-dev/2022-September/094849.html https://mail.openjdk.org/pipermail/core-libs-dev/2022-October/095086.html ThreadLocalRandom indeed does not go through the usual ThreadLocal path; however, it does occupy three fields (16 bytes) unconditionally in every Thread instance. So its use doesn't allocate *more* memory. In effect, the memory is already allocated, whether or not it's used. This might be an issue for virtual threads. Is TLR used so frequently that every virtual thread instance should pay for it? I think we should also tease apart the issues a bit. I see at least two separate problems here: 1) The Random class is an "embarrassment" as noted previously. 2) Collections.shuffle(List) effectively uses a shared, static Random instance. I believe that (1) is largely fixed by the addition of RandomGenerator, along with the ability to adapt RandomGenerator to any Random-consuming API using Random::from, and the addition of RandomGenerator overloads. For (2) instead of fiddling around with trying to fix the behavior of this old API, maybe we should just leave it in place, (and possibly even deprecate it) and update the docs to tell people to use RandomGenerator instead.
03-10-2022

> Potential concerns regarding use of TLR are additional memory consumption ThreadLocalRandom was re-engineered to have only one instance (with help from fields in Thread), so ThreadLocalRandom.current() does not allocate, so I expect no additional memory consumption. Loom folk may end up doing fiber local PRNG, but that shouldn't hold us up here. j.u.Random continues to be an embarrassment, and replacing uses with ThreadLocalRandom wherever we can is progress.
16-02-2019

Seems like a possibility. The default, static PRNG isn't specified at all. In particular, the application has no way to initialize its seed. Also, since the static PRNG is shared across the whole system, its state can be updated at any time outside the control of a particular application (e.g., by other parts of the JDK, or by third party libraries). Therefore, it seems unlikely that an application could have any dependence on having a single static PRNG implemented by j.u.Random used for shuffling. Potential concerns regarding use of TLR are additional memory consumption and changed order of classloading during initialization. These are likely to be surmountable, though.
16-02-2019