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