Is SharedSecrets thread-safe?

Johannes Kuhn info at j-kuhn.de
Tue Dec 29 21:17:30 UTC 2020


It's a bit more complicated - after all we are talking about the memory 
model and class loading.

There are some shared secrets that can be loaded later (e.g. AWT), when 
Threads are there.

The field is only set in one single place inside the JDK, so we are 
talking about 3 scenarios:

* The class is not yet loaded - the field is null, call 
ensureClassInitialized - which executes the class initializer on the 
current thread. A subsequent read of the field must be visible - as 
actions performed in the thread appear to be sequential for that thread.

* The class has been successfully loaded, everything relating to that is 
visible.

* The class is currently initialized by an other thread:
   * The first load of the field yields null - ensureClassInitialized 
blocks until the class has been loaded.
   * The first load yields something different than null.
     The question now is: can the second load yield the previous value?
     That is: can a field revert to it's original value?
     Other fields may not be visible yet (except if they have been frozen).
     So the big question is: can the second read return null after the 
first has found it to be a non-null value?

After reading the "Double checked locking is broken"[1] declaration 
again - it says that it does work for primitive values that can't be 
teared. The problem seems to be that the field of the referenced objects 
are not yet constructed.

The good news: the implementations of the shared secrets don't have 
fields. The better news: reference assignment also can't be teared.

- Johannes

[1]: https://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

On 29-Dec-20 18:53, Hans Boehm wrote:
> 
> 
> On Tue, Dec 29, 2020 at 5:56 AM Johannes Kuhn <info at j-kuhn.de 
> <mailto:info at j-kuhn.de>> wrote:
>  >
>  > Depends on what `initialize()` is.
>  >
>  > If it (at least) reads a volatile field, then the compiler can't reorder
>  > the second read before the first.
>  >
>  > - Johannes
> I disagree with this claim. I have no idea whether concurrency is 
> possible here, so it may not matter. See below.
> 
>  >
>  > On 29-Dec-20 14:42, 
> some-java-user-99206970363698485155 at vodafonemail.de 
> <mailto:some-java-user-99206970363698485155 at vodafonemail.de>
>  > wrote:
>  > > Hello,
>  > > the class `jdk.internal.access.SharedSecrets` provides getter 
> methods which all look similar to this:
>  > > ```
>  > > if (static_field == null) {
>  > >    initialize();
>  > > }
>  > > return static_field;
>  > > ```
> 
> If static_field is not volatile, and set concurrently, then the first 
> read of static_field may return non-null and the second null, without 
> initialize() even being executed. The Java memory model does not prevent 
> reordering of non-volatile reads from the same field (for good reason).
> 
> Even if initialize() is executed and performs a volatile read, this 
> reasoning doesn't hold. The initial static_field read may be delayed 
> past the volatile read inside the conditional and hence, at least 
> theoretically, past the second read. Control dependencies don't order 
> reads, either in Java, or in modern weakly-ordered architectures with 
> branch prediction. This doesn't matter if initialize() sets static_field.
> 
> This all assumes that having two threads call initialize() is OK.
> 
> Java code with data races is extremely tricky and rarely correct.
> 
> Hans


More information about the core-libs-dev mailing list