That would also be my understanding of the current situation, though this
contradicts what
Claes wrote.
Maybe the JVM behaves in a way which does not allow reordering, but the JLS
definitely seems
to allow it. Section § 12.2.4 [0] only mentions that for the class to be
initialized there
has to exist a lock LC (or at least the happens-before relationship), but there
is no
"freeze the world" or anything similar which would force a happens-before
relationship
for the code in `SharedSecrets`.
Maybe most of the `SharedSecrets` methods are thread-safe (albeit extremely
brittle) because
the classes to which the accessor objects belong to have previously already
been loaded
before `SharedSecrets` is used, therefore having already established a
happens-before
relationship.
However, this is definitely not the case for all of the methods as shown by the
following
example:
```
CookieHandler.setDefault(new CookieHandler() {
@Override
public void put(URI uri, Map<String, List<String>> responseHeaders) throws
IOException { }
@Override
public Map<String, List<String>> get(URI uri, Map<String, List<String>>
requestHeaders) throws IOException {
return Collections.emptyMap();
}
});
// Any site which uses cookies (i.e. Set-Cookie or Set-Cookie2 header)
URL url = new URL("https://oracle.com");
url.openConnection().getHeaderFields();
```
Running this code with `openjdk 15 2020-09-15` shows that the call to
`SharedSecrets.getJavaNetHttpCookieAccess()` is made before the class
`HttpCookie` has
been accessed and initialized. Therefore merely running this code in two
separate threads
(both having been started before the code is executed, since `Thread.start()`
establishes
a happens-before relationship) should be enough to render that `SharedSecrets`
method
non-thread-safe.
Kind regards
[0] https://docs.oracle.com/javase/specs/jls/se15/html/jls-12.html#jls-12.4.2
> Hans Boehm <[email protected]> hat am 29. Dezember 2020 um 18:53 geschrieben:
>
> 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