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 <i...@j-kuhn.de <mailto:i...@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-99206970363698485...@vodafonemail.de <mailto:some-java-user-99206970363698485...@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

Reply via email to