On Mon, 15 Mar 2021 23:31:33 GMT, Valerie Peng <[email protected]> wrote:
>> I would definitely not call `new SecureRandom()` each time as that can have
>> real performance problems (especially on systems which pull from
>> `/dev/random` and may not have hardware entropy). The synchronization
>> worries me too.
>>
>> Could `java.security.Security` contain a "provider version" `int` (volatile,
>> atomic, or similar) which is incremented every time the provider list is
>> changed? Then this class (clearly using some non-public API) would check
>> that value and if it is the same, just return the cached instance. If it has
>> changed since the last time, then it would update `instance` and its
>> remembered value of the index. I think that we might be able to do it
>> without taking any locks in this class because even if the providers change
>> out from under us, we returned a reasonable value (subject to
>> multi-threading) and will fix things up when we're called the next time.
>>
>> // using this and name collision to highlight what's a field and what's local
>> int providerListVersion = Security.nonPublicGetProviderListVersion();
>> if (this.providerListVersion != providerListVersion) {
>> this.providerListVersion = providerListVersion;
>> this.instance = new SecureRandom();
>> }
>> return this.instance;
>
> Or, I can also separate out the instance returned by getSecureRandom() so
> that code path should be unaffected, e.g.:
> // cached SecureRandom instance
> private static class CachedSecureRandomHolder {
> public static SecureRandom instance = new SecureRandom();
> private static Provider[] cachedConfig = Security.getProviders();
> private static SecureRandom def = instance;
>
> public static SecureRandom getDefault() {
> synchronized (CachedSecureRandomHolder.class) {
> Provider[] currConfig = Security.getProviders();
> if (!Arrays.equals(cachedConfig, currConfig)) {
> def = new SecureRandom();
> cachedConfig = currConfig;
> }
> }
> return def;
> }
> }
>
> /**
> * Get a SecureRandom instance. This method should be used by JDK
> * internal code in favor of calling "new SecureRandom()". That needs to
> * iterate through the provider table to find the default SecureRandom
> * implementation, which is fairly inefficient.
> */
> public static SecureRandom getSecureRandom() {
> return CachedSecureRandomHolder.instance;
> }
>
> /**
> * Get the default SecureRandom instance. This method is the
> * optimized version of "new SecureRandom()" which re-uses the default
> * SecureRandom impl if the provider table is the same.
> */
> public static SecureRandom getDefSecureRandom() {
> return CachedSecureRandomHolder.getDefault();
> }
Doesn't that still incur a JVM-wide lock whenever
`CachedSecureRandomHolder.getDefSecureRandom()` is called? I recall a
different JVM-wide lock in the `getInstance` path
([JDK-7107615](https://bugs.openjdk.java.net/browse/JDK-7107615)) creating
significant performance issues.
-------------
PR: https://git.openjdk.java.net/jdk/pull/3018