[OpenJDK 2D-Dev] [10] Review Request: 8185093 Expensive multi-core choke point when any graphics objects are created
Sergey Bylokhov
Sergey.Bylokhov at oracle.com
Tue Jul 25 22:37:30 UTC 2017
On 25.07.2017 15:03, Jim Graham wrote:
> On 7/25/17 12:53 PM, Sergey Bylokhov wrote:
>> In this variant the field should be volatile, and this will introduce
>> some synchronization. Otherwise it will be possible to read non-null
>> value in localEnv while the constructor of GraphicsEnvironment was not
>> completed on some other thread(but the field was assigned already > > Even though the assignment is the last statement in the method?
The assignment include these operations:
- Allocate memory
- Initialize the object
- Assign the object to the field.
These operation may be reordered, so some other thread can see non-null
reference in the field while initialization was not complete.
>
> In looking through the article that you sent out (only briefly) it looks
> like the consideration is that the initialization method run in one
> thread could reorder the instructions at run time so that the field is
> assigned before the initialization steps are done, even if the code is
> written with a different specific ordering.
>
> I'm guessing that the Java Memory Model ensures that membars are placed
> to protect static field initialization from similar dangers?
The key feature here is initialization of the class.
The next line will be blocked while the LocalGE class will not be
initialized:
return LocalGE.INSTANCE;
And initialization will start only when this code will run for the first
time.
>
> If that is the case then I think we have a few places where we do this
> "manual conditional synchronization" that should probably be
> investigated. If I remember correctly, though, they may use the
> following paradigm which might not suffer from that issue:
>
> Does it help if a local variable is used, as in:
>
> GE env = this.localEnv
> if (env == null) {
> synchronized (class) {
> if (this.localEnv == null) {
> localEnv = createGE();
> }
> env = this.localEnv;
> }
> }
> return env;
>
> This ensures that the second read from the field is done in the
> synchronized block for the case that it was originally found to be null,
> though this might not help if the line "localEnv = createGE()" can
> reorder code from inside the call to createGE() to code outside of it.
> However those dangling reordered stores should be resolved before it
> leaves the synchronized block, no?
I think that it is possible that one thread will do:
- create an object
- assign the object to the localEnv.
- Initialize the object.
And the second thread will do:
- Read non-null value from the this.localEnv to the env
- Check env to null
- Return non-initialized object.
> In any case, I can see that the code used in the webrev will eventually
> have no dead code at all in the final compiled version of the method
> whereas this version would minimally at least have a null check that
> must be executed even though it would be vestigial once the
> initialization was done...
>
> +1 for the inner class version - it's the most straightforward way to do
> this optimally...
--
Best regards, Sergey.
More information about the 2d-dev
mailing list