[concurrency-interest] Explicitly initializing volatile fields with default values

Vitaly Davidovich vitalyd at gmail.com
Thu Dec 17 19:06:10 EST 2015


On Thursday, December 17, 2015, Aleksey Shipilev <
aleksey.shipilev at oracle.com> wrote:

> Hi there, concurrency dwellers,
>
> I'm trying to find a counter-example/constraints against removing the
> field initializers for volatile fields, when those initializers are
> storing the default value. We know this improves performance, e.g.
>   https://bugs.openjdk.java.net/browse/JDK-8035284
>
> There is a gut feeling that removing these initializations is safe. But,
> I have heard rumors of traces of counter-examples in OpenJDK bugtracker,
> but found nothing substantial, which gives me doubts. Maybe there are
> constraints I am overlooking?
>
> First, let me show that you cannot (always) do this mechanically for all
> (even non-volatile!) usages. JLS 8.3.2.3 "Restrictions on the use of
> Fields during Initialization" allows this:
>
> public class InitializerOverwrite {
>   {
>     x1 = 42;
>     x2 = 42;
>   }
>
>   int x1;
>   int x2 = 0;
>
>   public static void main(String... args) {
>     InitializerOverwrite io = new InitializerOverwrite();
>     System.out.println(io.x1); // 42
>     System.out.println(io.x2); // 0
>   }
> }
>
> ...so you definitely need to inspect if there is some stray store that
> needs to be stamped out with the field initializer. What's worse,
> instance/field initializer can invoke an arbitrary method that might
> confuse any analysis, but still perform an instance field store. So, we
> can reliably do this optimization for simple cases only.
>
> But let's consider a simpler case for concurrency implications:
>
>  class C {
>    volatile int v = 0; // can we drop " = 0"?
>
>    public C() {
>      // nothing here
>    }
>  }
>
> Is there a plausible case that shows the semantical difference with
> field initializer storing a default value, and without one, that does
> *not* also affect single-threaded usages (i.e. it does not follow from
> the instance initialization sequence itself)?
>
> Naive attempts to construct the examples seem to boil down to two cases.
>
> *** Case A. Over-reaching "memory effects" for instance fields:
>
>  class A {
>    int f;
>    volatile int v = 0;
>
>    public A() {
>      f = 42;
>    }
>  }
>
>  A global;
>
>  ----
>
>  Thread 1:
>    global = new A();
>
>  Thread 2:
>    A a = global;
>    if (a != null && a.v == 0) {
>      print(a.f); // ?
>    }
>
> There are no guarantees here whatsoever, because field initializations
> are performed *before* any constructor body starts, as per JLS 12.5.
> Therefore, the "releasing" volatile store to $v is executed before any
> store to $f, which deconstructs any happens-before.
>
> This seems to expand to non-instance fields, and other variables written
> after firing the field initializer.
>
> Note, that perhaps moving the initialization ($v = 0) into the
> constructor after ($f = 42), or, similarly, making ($f = 42) the field
> initializer, would lay out the code in the correct shape, and this gets
> us to case B.
>
>
> *** Case B. Transitive "memory effects" over explicit stores:
>
>  class B {
>    int f = 42;
>    volatile int v = 0;
>  }
>
>  B global;
>
>  ----
>
>  Thread 1:
>    global = new B();
>
>  Thread 2:
>    B b = global;
>    if (b != null && b.v == 0) {
>      print(b.f); // ?
>    }
>
> These three executions seem plausible:
>
>  1) Happens-before read of write(f, 42):
>
>   (default) write(v,0)
>   (default) write(f,0)
>          |
>          | hb/sw
>          v
>      write(f,42) --hb/po--> write(v,0)
>                                 |
>                                 | hb/sw
>                                 v
>                              read(v):0 --hb/po--> read(f):42;
>
>  2) Read of default write(f, 0) -- these synchronize-with the first
> action in the thread:
>
>                        (default) write(v,0)
>                        (default) write(f,0)
>                                 |
>                                 | hb/sw
>                                 v
>                              read(v):0 --hb/po--> read(f):0
>
>  (One might wonder if that means you can see the default value for an
> explicitly initialized volatile field, once you read the instance itself
> -- you can! -- we have seen this with AtomicIntegers before)


Aren't instance fields initialized in textual order according to JLS? It's
not clear to me how this would be allowed.  In particular, if volatile
writes in ctor are supposed to have same ordering constraints as final
field writes (that's supposedly going to be stated in next JMM revision),
how was it possible to see AtomicInteger field with default value?



>
>  3) Racy read of unordered write(f, 42):
>
>      (default) write(v,0)
>      (default) write(f,0)          write(f, 42)
>                   |                     .
>                   | hb/sw               . (unordered)
>                   v                     .
>                read(v):0 --hb/po--> read(f):42
>
>
> In other words, if we drop execution (1) by omitting the explicit
> initializing store, we would still be able to observe both "0" and "42".
>
> This seems to expand to non-instance fields, and other variables written
> before firing the field initializer.
>
> *** Putting all together
>
> Now, putting these things together:
>
>  * Case A tells that no variable written *after* the volatile instance
> field initializer is protected (duh).
>
>  * Case B tells that no variable written *before* the volatile instance
> field initializer writing the default value is protected by
> happens-before. This is because the explicit initializing store with the
> default value is indistinguishable from the default value store.
>
>  * Since Case A and Case B cover all possible variables (with the
> exception of the volatile field itself), this seems to imply that
> explicit field initializers that store default values have no effect on
> memory ordering.
>
> Is it a correct way to think about it?
>
> Thanks,
> -Aleksey
>
>

-- 
Sent from my phone
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20151217/b40aa6fd/attachment.html>


More information about the Concurrency-interest mailing list